/* **********************************************************************
 * *                                                                    *
 * *             BITE Driver Program Interface Routines                 *
 * *                                                                    *
 * **********************************************************************
 * File: libs/antenna/bite_driver.c
 *
 *            COPYRIGHT (c) 1991, 1993, 1999, 2001, 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 "setup.h"
#include "user_lib.h"
#include "antenna_lib.h"
#include "antenna_int.h"
#include "config_lib.h"
#include "ant_global.h"

static void BiteCheckField
( struct bitex_field_def *pf,
  volatile const struct bitex_setup *bitex_a );
static void fixup_string( char *stext_a, SINT4 ilen_a ) ;
static void QBiteUpdateOne
(SINT4 iField_a,
 volatile const struct bitex_field_def *pField_a );
static void BiteUpdateOne
(SINT4 iField_a,
 volatile const struct bitex_field_def *pField_a );

#define CLAMP( ITEM, SIZE ) ITEM = MAX( 0, MIN( (SIZE), (ITEM) ) )

/* ------------------------------
 * Get a copy of the complete bitex definition structures from
 * the driver.  Returns TRUE if a fresh copy is required, i.e.,
 * the driver definitions have changed since the last time that
 * this routine was called.  FALSE return leaves structures
 * unchanged and returns immediately.
 */
UINT2 lbite_get_def
( struct bitex_setup *bitex_a,	/* May be NULL */
  UINT2 lforce_load_a )
{
  UINT2 lloaded ;
  static UINT4 ibite_setup_serialnum = 0xFFFF0000 ;

  if( (ibite_setup_serialnum != antGlobal_c->ibite_setup_serialnum) ||
      lforce_load_a ) {

    if( bitex_a )  /* Cast removes volatile */
      *bitex_a = ((struct antenna_global*)antGlobal_c)->bitex ;

    ibite_setup_serialnum = antGlobal_c->ibite_setup_serialnum ;
    lloaded = TRUE ;

  } else {
    lloaded = FALSE ;
  }
  return( lloaded ) ;
}

/* ------------------------------
 * Get a copy of a single field of the bitex definition from the driver.
 */
void bite_get_one_def
( struct bitex_field_def *definition_a,
  SINT4 ifield_a )
{
  if( (ifield_a >=0) && (ifield_a < BITE_NUM_FIELD_DEFS) )
    { /* Cast discards volatile */
      *definition_a = ((struct antenna_global*)antGlobal_c)->bitex.fields[ifield_a] ;
    }
  else
    {
      memset( definition_a, 0, sizeof(struct bitex_field_def) ) ;
    }
}

/* ------------------------------
 * Give a new copy of the bitex definition structures to the
 * driver.  Perform as much checking as possible on the structures
 * prior to loading into shared memory.
 */
void bite_set_def( const struct bitex_setup *bitex_a )
{
  SINT4 ifield, iunit ; struct bitex_setup bitex = *bitex_a ;

  /* Checkup the top definitions
   */
  CLAMP( bitex.ifield_cnt, BITE_NUM_FIELD_DEFS ) ;
  CLAMP( bitex.iunit_cnt , BITE_MAX_UNITS      ) ;

  for( iunit=0 ; iunit < BITE_MAX_UNITS ; iunit++ ) 
    {
      bitex.units[iunit].iunit_length =
	CLAMP( bitex.units[iunit].iunit_length, BITE_MAX_LENGTH ) ;
      /* We do not allow Q-BITE control units currently. */
      if (bitex.units[iunit].lQBite)
	bitex.units[iunit].lcontrol_unit = FALSE;
    }

  /* Checkup the individual fields.  If the unit number and byte
   * number are not within bounds then force the field to be
   * disabled but do not make any other changes to it for now.
   */
  for( ifield=0 ; ifield < BITE_NUM_FIELD_DEFS ; ifield++ ) {
    BiteCheckField( &bitex.fields[ifield], &bitex ) ;
  }
  
  /* Copy the structures into shared memory, and increment the
   * serial number of this version so that other processes can
   * detect when an update has been posted.
   */
  antGlobal_c->bitex = bitex ;
  antGlobal_c->ibite_setup_serialnum++ ;

  /* Rescan to update the data and fault bits
   */
  antGlobal_c->binfo.lcnt_send_changed = TRUE ;
  bite_local_update(WILD_UNIT) ;
  bite_fault_update() ;
}

/* ------------------------------
 * Set just one bit definition field.  Perform as much checking
 * as possible on the structures prior to loading into shared
 * memory.
 */
void bite_set_one_def
( const struct bitex_field_def *pDefinition_a,
  SINT4 iField_a )
{
  struct bitex_field_def FieldDef;

  if( (iField_a<0) || (iField_a >= BITE_NUM_FIELD_DEFS) ) return;

  /* Checkup the new field.
   */
  FieldDef = *pDefinition_a;
  BiteCheckField( &FieldDef, &antGlobal_c->bitex );
  
  /* Copy the structures into shared memory, and increment the serial
   * number of this version so that other processes can detect when
   * an update has been posted.
   */
  /* Cast discards volatile */
  ((struct antenna_global *)antGlobal_c)->bitex.fields[iField_a] = FieldDef;
  antGlobal_c->ibite_setup_serialnum++ ;

  /* Rescan to update the data and fault bits
   */
  antGlobal_c->binfo.lcnt_send_changed = TRUE ;
  bite_local_update(FieldDef.iunit) ;
  bite_fault_update() ;
}

/* ------------------------------
 * Checkup an individual field.  If the unit number and byte
 * number are not within the bounds implied by the TOP_DEFs,
 * then force the field to be disabled but do not make any
 * other changes to it for now.
 */
static void BiteCheckField
( struct bitex_field_def *pf_a,
  volatile const struct bitex_setup *bitex_a )
{
  if( pf_a->iunit > BITE_MAX_UNITS-1  ) pf_a->iunit = BITE_MAX_UNITS-1 ;
  if( pf_a->ibyte < 2                 ) pf_a->ibyte = 2 ;
  if( pf_a->ibyte > BITE_MAX_LENGTH-2 ) pf_a->ibyte = BITE_MAX_LENGTH-2 ;
  
  if( (pf_a->ldisabled == FALSE) &&
      ((pf_a->iunit >=  bitex_a->iunit_cnt                        ) || 
       (pf_a->ibyte >= (bitex_a->units[pf_a->iunit].iunit_length - 1))) )
    {
      pf_a->ldisabled = TRUE ;
    }
  if( pf_a->ldisabled == FALSE )
    {
      if( bitex_a->units[ pf_a->iunit ].lQBite)
	{
	  struct qbite_status_info *psts = &(pf_a->cs.Q_Sts);
	  if ( pf_a->ibit > 5) pf_a->ibit = 5;
	  if ( pf_a->ibit < 1) pf_a->ibit = 1;
	  fixup_string( psts->sUnitsText , sizeof(psts->sUnitsText ) ) ;
	  CLAMP( psts->iFormatLeft, 9 ) ;
	  CLAMP( psts->iFormatRight, 9 ) ;
	}
      else
	{
	  CLAMP( pf_a->ibit , 6 ) ;
	  
	  if( bitex_a->units[ pf_a->iunit ].lcontrol_unit ) 
	    {
	      struct bitex_control_info *pcnt = &pf_a->cs.cnt ;
	      CLAMP( pcnt->fcolor_fieldnum, BITE_NUM_FIELD_DEFS-1 ) ;
	      fixup_string( pcnt->in_text , sizeof(pcnt->in_text ) ) ;
	      fixup_string( pcnt->out_text, sizeof(pcnt->out_text) ) ;
	    }
	  else
	    {
	      struct bitex_status_info  *psts = &pf_a->cs.sts ;
	      CLAMP( psts->disable_field, BITE_NUM_FIELD_DEFS-1   ) ;
	      fixup_string( psts->low_text , sizeof(psts->low_text ) ) ;
	      fixup_string( psts->high_text, sizeof(psts->high_text) ) ;
	    }
	}
    }
}

/* ------------------------------
 * Routine to check that a string of a certain length does indeed
 * contain a NULL somewhere, and insert on at the end if not.
 */
static void fixup_string( char *stext_a, SINT4 ilen_a )
{
  SINT4 ii ;
  for( ii=0 ; ii < ilen_a ; ii++ ) if( stext_a[ii] == '\0' ) return ;
  stext_a[ ilen_a - 1 ] = '\0' ;
}

/* ------------------------------
 * Save the definition information.
 */
MESSAGE bite_save_def( void )
{
  MESSAGE istatus = bitex_save_conf( NULL, &antGlobal_c->bitex ) ;
  return( istatus ) ;
}

/* ------------------------------
 * Load the definition information.  Read the data into local
 * memory, then pass into the driver with error checking and
 * updates.
 */
MESSAGE bite_load_def( void )
{
  struct bitex_setup bitex ;
  MESSAGE istatus = bitex_load_conf( NULL, &bitex ) ;


  if( istatus == SS_NORMAL ) bite_set_def( &bitex ) ;
  return( istatus ) ;
}

/* ------------------------------
 * Get the current mask of one bit for each defined field.  There
 * is a maximum of BITE_NUM_FIELD_DEFS bits returned.
 */
void BiteGetMasks
( UINT4 iData_a[BITE_MASK_SIZE], 
  UINT4 iFault_a[BITE_MASK_SIZE],
  UINT4 iCritical_a[BITE_MASK_SIZE] )
{
  SINT4 iIndex;
  for (iIndex=0; iIndex<BITE_MASK_SIZE; iIndex++)
    {
      iData_a[iIndex]     = antGlobal_c->binfo.data_mask[iIndex];
      iFault_a[iIndex]    = antGlobal_c->binfo.FaultMask[iIndex];
      iCritical_a[iIndex] = antGlobal_c->binfo.CriticalMask[iIndex];
    }
}

/* ------------------------------
 * Get the button presses flagged for IRIS.  The flags are cleared,
 * so we only see presses since the last call.
 */
void  bite_get_iris_flags
( UINT4 iMask_a[BITE_MASK_SIZE] )
{
  SINT4 iIndex;
  for (iIndex=0; iIndex<BITE_MASK_SIZE; iIndex++)
    {
      iMask_a[iIndex] = antGlobal_c->binfo.IrisFlagMask[iIndex];
      antGlobal_c->binfo.IrisFlagMask[iIndex] = 0;
    }  
}

/* ------------------------------
 * Get all temporal information about a field.
 */
void  bite_get_field_state
( struct bite_field_state *fstate_a, SINT4 ifield_a )
{
  UINT1 lFaultable;
  SINT4 ifield = ifield_a ;
  volatile struct bitex_field_def *pfdef ;

  CLAMP( ifield, BITE_NUM_FIELD_DEFS-1 ) ;
  pfdef = &antGlobal_c->bitex.fields[ifield] ;

  /* Clear unused data */
  memset( fstate_a, 0, sizeof(*fstate_a) );

  /* Handle control versus status fields.
   */
  fstate_a->lQBite   = antGlobal_c->bitex.units[pfdef->iunit].lQBite ;
  fstate_a->lcontrol = antGlobal_c->bitex.units[pfdef->iunit].lcontrol_unit ;

  {
    SINT4 ibyte = (ifield >> 5), ibit = (ifield & 0x1F) ;
    fstate_a->ldata          = BTEST( antGlobal_c->binfo.data_mask   [ibyte], ibit ) ;
    fstate_a->lfault         = BTEST( antGlobal_c->binfo.FaultMask   [ibyte], ibit ) ;
    fstate_a->lCriticalFault = BTEST( antGlobal_c->binfo.CriticalMask[ibyte], ibit ) ;
    lFaultable       = BTEST( antGlobal_c->binfo.FaultableMask[ibyte], ibit ) ;
  }

  /* Set colors.  This will be overridden in the case of the
   * control buttons. 
   */
  if (lFaultable)
    {
      if (fstate_a->lCriticalFault)
	{
	  fstate_a->label_color  = BITE_COLOR_RED ;
	  fstate_a->button_color = BITE_COLOR_RED ;
	}
      else if (fstate_a->lfault)
	{
	  fstate_a->label_color  = BITE_COLOR_YELLOW ;
	  fstate_a->button_color = BITE_COLOR_YELLOW ;
	}
      else
	{
	  fstate_a->label_color  = BITE_COLOR_GREEN ;
	  fstate_a->button_color = BITE_COLOR_GREEN ;
	}
    }
  else
    {
      fstate_a->label_color  = BITE_COLOR_NONE ;
      fstate_a->button_color = BITE_COLOR_NONE ;
    }

  if (fstate_a->lQBite)
    {
      char sLabel[60], sFormat[40];
      struct qbite_status_info QInfo;

      QInfo = ((struct bitex_field_def*)pfdef)->cs.Q_Sts;
      fstate_a->fQBiteValue = antGlobal_c->binfo.fQBiteValues[ifield];

      sprintf( sFormat, "%%%d.%df %%s", QInfo.iFormatLeft+QInfo.iFormatRight+1,
	       QInfo.iFormatRight);
     
      sprintf( sLabel, sFormat, fstate_a->fQBiteValue, QInfo.sUnitsText );
      strncpy( fstate_a->label_text, sLabel, BITE_LABEL_TEXT_SIZE-1 );
      fstate_a->label_text[BITE_LABEL_TEXT_SIZE-1] = 0;
    }
  else
    {
      /* Fill in data and fault conditions from the packed bits that
       * the driver maintains.
       */
      fstate_a->fQBiteValue = 0.0;
      if( fstate_a->lcontrol ) 
	{
	  fstate_a->lCriticalFault = FALSE;
	  /* Control Field.  Button state is deduced from the data, and button
	   * and text colors may be a function of other fields.
	   */
	  fstate_a->lbutton_in = (fstate_a->ldata == pfdef->cs.cnt.lbutton_in_high) ;
	  fstate_a->liris_flag = (fstate_a->ldata && pfdef->cs.cnt.liris_flag) ;
	  
	  fstate_a->button_color = fstate_a->lbutton_in ? pfdef->cs.cnt.button_in_color :
	    pfdef->cs.cnt.button_out_color ;
	  {
	    SINT4 index = pfdef->cs.cnt.fcolor_fieldnum ;
	    UINT2 lbit = BTEST( antGlobal_c->binfo.data_mask[index >> 5], (index & 0x1F) ) ;
	    
	    if( ((pfdef->cs.cnt.fcolor_state == BITE_BIT_LOW ) && (lbit == FALSE)) ||
		((pfdef->cs.cnt.fcolor_state == BITE_BIT_HIGH) && (lbit == TRUE )) )
	      {
		/* Override button color */
		fstate_a->label_color  = pfdef->cs.cnt.fcolor_color ;
		fstate_a->button_color = pfdef->cs.cnt.fcolor_color;
	      }
	    else
	      /* Do not override button color */
	      fstate_a->label_color = BITE_COLOR_NONE ;
	  }
	  if( fstate_a->lbutton_in )
	    strncpy( fstate_a->label_text, (char *)pfdef->cs.cnt.in_text,
		     BITE_LABEL_TEXT_SIZE-1 ) ;
	  else
	    strncpy( fstate_a->label_text, (char *)pfdef->cs.cnt.out_text,
		     BITE_LABEL_TEXT_SIZE-1 ) ;
	  fstate_a->label_text[BITE_LABEL_TEXT_SIZE-1] = 0;
	  
	} 
      else
	{
	  /* Status Field.  Text color is RED if there is a warning, and buttons
	   * are never colored.
	   */
	  fstate_a->lbutton_in = FALSE ;
	  fstate_a->liris_flag = FALSE ;
	  
	  if( fstate_a->ldata )
	    strncpy( fstate_a->label_text, (char *)pfdef->cs.sts.high_text, 
		     BITE_LABEL_TEXT_SIZE-1 ) ;
	  else
	    strncpy( fstate_a->label_text, (char *)pfdef->cs.sts.low_text,
		     BITE_LABEL_TEXT_SIZE-1 ) ;
	  fstate_a->label_text[BITE_LABEL_TEXT_SIZE-1]=0;
	}
    }
}

/* ------------------------------
 * Get the current flag.  Set to zero if there is no error to flag
 */
void bite_get_flag
( UINT4* iFlag_a, SINT4 *ifield_a )
{
  *iFlag_a  = antGlobal_c->binfo.iFaultSummaryFlag ;
  *ifield_a = antGlobal_c->binfo.ifault_field ;
}

/* ------------------------------
 * Get the activity counts for the number of bite units specified.
 */
SINT4 bite_get_activity( SINT4 in_count_a[], SINT4 out_count_a[], 
			SINT4 bite_count_a )
{
  SINT4 iunit, iMaxUnits;
  iMaxUnits = MIN( bite_count_a, BITE_MAX_UNITS );

  for (iunit=0; iunit<iMaxUnits; iunit++)
    {
      in_count_a[iunit]  = antGlobal_c->binfo.Unit[iunit].iin_cnt;
      out_count_a[iunit] = antGlobal_c->binfo.Unit[iunit].iout_cnt;
    }

  if (iMaxUnits > (SINT4)(UINT4)antGlobal_c->bitex.iunit_cnt)
    iMaxUnits = (SINT4)(UINT4)antGlobal_c->bitex.iunit_cnt;

  return iMaxUnits;
}

/* ------------------------------
 * Get the time since the last transmission was received for the number of
 * bite units specified.
 */
void bite_get_age( SINT4 age_a[], SINT4 bite_count_a )
{
  UINT4 iunit, ibtime;

  getbtime( &ibtime );
  for (iunit=0;(iunit<bite_count_a)&&(iunit<BITE_MAX_UNITS);iunit++)
    {
      age_a[iunit] = btimeGrace( ibtime - antGlobal_c->binfo.Unit[iunit].ibtime ) ;
    }
}

/* ------------------------------
 * Send a command to the BITE unit.  The particular command is specified 
 * by the argument.
 */
void   bite_send_command( UINT1 icommand_a ) {
  AntSetArg( ANTSET_BITESCMD, icommand_a ) ; }
void __bite_send_command( UINT1 icommand_a )
{
  switch (icommand_a)
    {
    case BITE_INTERROGATE:
      antGlobal_c->binfo.lInterrogateBite = TRUE;  /* Request external updates */
      antGlobal_c->binfo.lcnt_send_asap   = TRUE;  /* Transmit control updates */
      break;

    case BITE_TAKE_SAMPLE:
      antGlobal_c->binfo.lSampleBite = TRUE;
      break;

    case BITE_SET_VALUES:
      antGlobal_c->binfo.lSetValuesBite = TRUE;
      break;

    case BITE_RESET:
      antGlobal_c->binfo.lResetBite = TRUE;
      break;

    default:
      break;
    }
}

/* ------------------------------
 * Sends one of the following commands to a specified BITE unit:
 *   BITE_INTERROGATE: Request a new BITE packet transmission from the RCP
 *   BITE_SET_VALUES:  Request that RCP send commands to external units
 *   BITE_TAKE_SAMPLE: Request that RCP sample data from external units
 *   BITE_RESET:       Reset the hardware associated with this BITE unit
 */
void   bite_send_unit_command( UINT1 iCommand_a, UINT1 iUnitId_a ) {
  AntSetArg2( ANTSET_BITEUCMD, iCommand_a, iUnitId_a ) ; }
void __bite_send_unit_command( UINT1 iCommand_a, UINT1 iUnitId_a )
{
  UINT1 iUnit;
  for( iUnit=0 ; iUnit < antGlobal_c->bitex.iunit_cnt ; iUnit++ )
    {
      volatile struct bitex_unit_info *pBitex=&(antGlobal_c->bitex.units[iUnit]);
      
      if( (!pBitex->lcontrol_unit ) && (iUnitId_a == pBitex->iunit_id))
	{
	  volatile struct bite_unit_info *pBite=&(antGlobal_c->binfo.Unit[iUnit]);
	  switch (iCommand_a)
	    {
	    case BITE_INTERROGATE:
	      pBite->lInterrogate = TRUE;  break;
	      
	    case BITE_TAKE_SAMPLE:
	      pBite->lSample = TRUE;       break;

	    case BITE_SET_VALUES:
	      pBite->lSetValues = TRUE;    break;
	      
	    case BITE_RESET:
	      pBite->lReset = TRUE;        break;
	    }
	}
    }
}

/* ------------------------------
 * Check whether there is a BITE field with a particular (reserved) text
 * name, and if so, return the state of that bit.
 */
UINT2 bite_check_keyname( const char *keyname_a )
{
  SINT4 ifield ; UINT2 iresult = BITE_CHKEY_UNDEF ;

  /* Check for a match with the name in all defined fields that
   * are also enabled.
   */
  for( ifield=0 ; ifield < antGlobal_c->bitex.ifield_cnt ; ifield++ ) {
    volatile struct bitex_field_def *pfield = &antGlobal_c->bitex.fields[ifield] ;
    char *pname = (char *)pfield->name_text ;

    if( ( pfield->ldisabled               == FALSE ) &&
	( strncmp( pname, keyname_a, 20 ) == 0     ) ) {

      volatile struct bite_info *pbinfo = &antGlobal_c->binfo ;
      UINT1 ldata = BTEST( pbinfo->data_mask[ifield >> 5], (ifield & 0x1F) ) ;

      if( ldata ) iresult = BITE_CHKEY_TRUE  ;
             else iresult = BITE_CHKEY_FALSE ;
      break ;
    }
  }
  return( iresult ) ;
}

/* ------------------------------
 * Set the button of a control field to the indicated state.  If the
 * field is a status field, then this routine is a NOP.
 */
void   bite_set_button( UINT2 lbutton_in_a, SINT4 ifield_a ) { 
  AntSetArg2( ANTSET_BITEBUTN, lbutton_in_a, ifield_a ) ; }
void __bite_set_button( UINT2 lbutton_in_a, SINT4 ifield_a )
{
  SINT4 ifield = ifield_a ;
  volatile struct bitex_field_def *pfdef ;

  CLAMP( ifield, BITE_NUM_FIELD_DEFS-1 ) ;
  pfdef = &antGlobal_c->bitex.fields[ifield] ;

  if( antGlobal_c->bitex.units[ pfdef->iunit ].lcontrol_unit ) {
    if( ( 0 != lbutton_in_a                  ) ==
	( 0 != pfdef->cs.cnt.lbutton_in_high ) )
      antGlobal_c->binfo.data_mask[ ifield >> 5 ] |=  (1 << (ifield & 0x1F)) ;
    else
      antGlobal_c->binfo.data_mask[ ifield >> 5 ] &= ~(1 << (ifield & 0x1F)) ;

    /* Set flag for IRIS */
    if (pfdef->cs.cnt.liris_flag) 
      antGlobal_c->binfo.IrisFlagMask[ ifield>>5 ] |= (1 << (ifield & 0x1F)) ;

    antGlobal_c->binfo.lcnt_send_changed = TRUE ;
    bite_fault_update() ;
  }
}

/* ------------------------------
 * Request that a client send a BITE status packet.  The full packet
 * is provided, and some error checking is done.
 */
MESSAGE bite_send_client_status
( SINT4 iUnit_a,            /* Packet unit number, origin 0 */
  const UINT1 iPacket_a[],  /* Packet to send */
  SINT4 iPacketLength_a )   /* Number of bytes in packet */
{
  int iByte;
  volatile struct bite_unit_info  *pBite;
  volatile struct bitex_unit_info *pBitex;

  if ((iUnit_a<0)||(iUnit_a>=(SINT4)(UINT4)antGlobal_c->bitex.iunit_cnt)) 
    return ANT_BITE_STATUS_UNIT;

  pBitex = &antGlobal_c->bitex.units[iUnit_a];
  
  if ( pBitex->lcontrol_unit )                    return ANT_BITE_STATUS_UNIT;

  if ( pBitex->iunit_length != iPacketLength_a )  return ANT_BITE_STATUS_SIZE;

  if ( pBitex->iunit_length > BITE_MAX_LENGTH )   return ANT_BITE_STATUS_SIZE;

  pBite = &antGlobal_c->binfo.Unit[iUnit_a];

  if ( pBite->bClientPacket )  return ANT_BITE_STATUS_BUSY;

 /*Cast discards volatile*/
  memcpy( (UINT1*)pBite->sClientPacket, iPacket_a, iPacketLength_a );

  /* Set up pre determined contents of the packet */
  if (pBitex->lQBite)
    pBite->sClientPacket[0] = ANT_SYNC_QBITE;
  else
    pBite->sClientPacket[0] = ANT_SYNC_BITE;
  pBite->sClientPacket[1] = pBitex->iunit_id;
  for (iByte=2; iByte<pBitex->iunit_length; iByte++)
    {
      pBite->sClientPacket[iByte] &= 0x7f;
    }
  pBite->sClientPacket[pBitex->iunit_length-1] = ANT_SYNC_ENDREC;

  pBite->bClientPacket = TRUE;

  return SS_NORMAL;

}

/* ------------------------------
 * This function processes the received BITE packets and formats the data
 * into an array of BITE_NUM_FIELD_DEFS bits.  Fault conditions are checked
 * after all data bits are set.
 */
void bite_local_update
( SINT4 iUnit_a )
{
  SINT4 iField ;

  /* Loop through all of the defined status fields, computing the
   * data value for each one as we go.  Ignore control fields, as
   * they do not depend on the incoming data stream.
   */
  for( iField=0 ; iField < antGlobal_c->bitex.ifield_cnt ; iField++ )
    {
      volatile struct bitex_field_def *pField = &antGlobal_c->bitex.fields[iField] ;

      if ((iUnit_a==WILD_UNIT)||(iUnit_a==pField->iunit))
	{
	  volatile struct bitex_unit_info *pUnit  = &antGlobal_c->bitex.units[pField->iunit];
	  if( (pField->ldisabled == FALSE) && (pUnit->lcontrol_unit == FALSE) )
	    {
	      if (pUnit->lQBite)
		{
		  /* Q-BITE data processed here */
		  QBiteUpdateOne( iField, pField );
		}
	      else
		{
		  /* Regular BITE data processed here */
		  BiteUpdateOne( iField, pField );
		}
	    }
	}
    }
}
/* ------------------------------
 * Update one Q-BITE field from the input data stream
 */
static void QBiteUpdateOne
(SINT4 iField_a,
 volatile const struct bitex_field_def *pField_a )
{
  FLT4  fValue;
  SINT4 iValue, iByte, iSize, iCount;
  iByte = (SINT4)(UINT4)pField_a->ibyte;
  iSize = (SINT4)(UINT4)pField_a->ibit;

  /* The last byte is the most significant */
  iByte += iSize-1;
  iValue = antGlobal_c->binfo.Unit[pField_a->iunit].sbite_reception[iByte];
  /* Sign extend the number, if applicable */
  if ((pField_a->cs.Q_Sts.lSigned)&&(iValue &0x40)) iValue |= 0xFFFFFF80;

  for (iCount=1; iCount<iSize; iCount++)
    {
      iByte--;
      iValue = iValue << 7;
      iValue += antGlobal_c->binfo.Unit[pField_a->iunit].sbite_reception[iByte];
    }

  fValue = (FLT4)iValue;
  fValue *= pField_a->cs.Q_Sts.fCalSlope;
  fValue += pField_a->cs.Q_Sts.fCalOffset; 
  antGlobal_c->binfo.fQBiteValues[iField_a] = fValue;
}
/* ------------------------------
 * Update one BITE field from the input data stream
 */
static void BiteUpdateOne
(SINT4 iField_a,
 volatile const struct bitex_field_def *pField_a )
{
  SINT4 ibyte = (iField_a >> 5) ; UINT4 ibit = 1 << (iField_a & 0x1F) ;
  
  if( BTEST( antGlobal_c->binfo.Unit[pField_a->iunit].sbite_reception[pField_a->ibyte],
	     pField_a->ibit ) )
    {
      antGlobal_c->binfo.data_mask[ibyte] |=  ibit ;
    }
  else 
    {
      antGlobal_c->binfo.data_mask[ibyte] &= ~ibit ;
    }
}
/* ------------------------------
 * Run through each of the defined status fields and set all
 * non-disabled fault bits.  Note that the disabling conditions
 * may be due to either status fields or control fields.
 */
void bite_fault_update( void )
{
  SINT4 iField ; UINT2 iTotalFault = BITE_FLAG_OK ;

  /* Loop through unused fields to make sure they are cleared */
  for( iField=0 ; iField < BITE_NUM_FIELD_DEFS; iField++ )
    {
      volatile struct bitex_field_def *pfield = &antGlobal_c->bitex.fields[iField] ;
      volatile struct bitex_unit_info *pUnit  = &antGlobal_c->bitex.units[pfield->iunit];
      SINT4 ibyte = (iField >> 5) ; UINT4 ibit = 1 << (iField & 0x1F) ;
      
      if ( (iField < antGlobal_c->bitex.ifield_cnt ) && (pfield->ldisabled == FALSE) &&
	   (pUnit->lcontrol_unit == FALSE) )
	{
	  UINT1 lFaultable, lFault, lCritical;
	  if (pUnit->lQBite)
	    {
	      volatile struct qbite_status_info *psts = &pfield->cs.Q_Sts ;
	      FLT4 fData = antGlobal_c->binfo.fQBiteValues[iField];

	      lFaultable = FALSE;

	      /* Check for critical faults */
	      if (psts->iFaultMask&QBITE_CRITICAL)
		{
		  lFaultable = TRUE;
		  if (psts->iFaultMask&QBITE_LESSTHAN)
		    lCritical = (fData < psts->fCriticalThreshold);
		  else
		    lCritical = (fData > psts->fCriticalThreshold);
		}
	      else
		lCritical = FALSE;

	      /* Check for faults */
	      if (psts->iFaultMask&QBITE_FAULT)
		{
		  lFaultable = TRUE;
		  if (psts->iFaultMask&QBITE_LESSTHAN)
		    lFault = (fData < psts->fFaultThreshold);
		  else
		    lFault = (fData > psts->fFaultThreshold);
		}
	      else
		lFault = FALSE;
	    }
	  else
	    {
	      volatile struct bitex_status_info *psts = &pfield->cs.sts ;
	      UINT1 ldata = ((antGlobal_c->binfo.data_mask[ibyte] & ibit) != 0) ;
	      
	      lFaultable =
		(psts->flag_state == BITE_BIT_LOW ) || (psts->flag_state == BITE_BIT_HIGH);

	      lFault = ((psts->flag_state == BITE_BIT_LOW ) && (ldata == FALSE)) ||
		((psts->flag_state == BITE_BIT_HIGH) && (ldata == TRUE )) ;
	      
	      /* If we have a field which is faultable, then
	       * check for any disabling conditions.
	       */
	      if (lFaultable)
		{
		  SINT4 idisab = psts->disable_field ;
		  
		  if( antGlobal_c->bitex.fields[idisab].ldisabled == FALSE )
		    {
		      UINT2 lfdata = BTEST( antGlobal_c->binfo.data_mask[idisab >> 5],
					    (idisab & 0x1F) ) ;
		      if (((psts->disable_state==BITE_BIT_LOW ) && (!lfdata)) ||
			  ((psts->disable_state==BITE_BIT_HIGH) && (lfdata)))
			{
			  lFault=FALSE ;
			  lFaultable=FALSE ;
			}
		    }
		}
	      lCritical =  ( lFault && (psts->iFlags & BITE_SF_CRITICAL ));
	    }

	  /* Fill in fault bits, and keep track of the first one seen.
	   */
	  if( lCritical )
	    {
	      /* Critical faults */
	      antGlobal_c->binfo.CriticalMask[ibyte] |= ibit ;
	      if( (iTotalFault==BITE_FLAG_OK)||(iTotalFault==BITE_FLAG_FAULT) )
		{
		  iTotalFault = BITE_FLAG_CRITICAL;
		  antGlobal_c->binfo.ifault_field = iField ;
		}
	    }
	  else
	    {
	      antGlobal_c->binfo.CriticalMask[ibyte] &= ~ibit ;
	    }
	  if( lFault )
	    {
	      /* Normal faults */
	      antGlobal_c->binfo.FaultMask[ibyte] |= ibit ;
	      if( iTotalFault==BITE_FLAG_OK )
		{
		  iTotalFault = BITE_FLAG_FAULT;
		  antGlobal_c->binfo.ifault_field = iField ;
		}
	    }
	  else
	    {
	      antGlobal_c->binfo.FaultMask[ibyte] &= ~ibit ;
	    }
	  if (lFaultable)
	    antGlobal_c->binfo.FaultableMask[ibyte] |= ibit ;
	  else
	    antGlobal_c->binfo.FaultableMask[ibyte] &= ~ibit ;
	}
      /* Undefined, disabled, or control fields, can not possibly
       * generate any faults.
       */
      else
	{
	  antGlobal_c->binfo.FaultMask[ibyte]     &= ~ibit ;
	  antGlobal_c->binfo.CriticalMask[ibyte]  &= ~ibit ;
	  antGlobal_c->binfo.FaultableMask[ibyte] &= ~ibit ;
	}
    }
  
  /* Fill in global copy of overall fault detection.
   */
  antGlobal_c->binfo.iFaultSummaryFlag = iTotalFault ;
  if( iTotalFault == BITE_FLAG_OK ) antGlobal_c->binfo.ifault_field = 0 ;
}

/* ------------------------------
 * Get the diagnostic buffer containing the last transmission starting with
 * a C0 hex which had a syntax error.
 * Entry parameters:
 *    ibuf_size_a - The size of the buffer in bytes
 * Exit parameters:
 *    sbuffer_a    - Buffer with stuff in it
 *    ifill_size_a - Number of characters placed in the buffer
 */
void bite_get_diagnostic
  ( UINT1* sbuffer_a, 
   SINT4 ibuf_size_a, 
   SINT4* ifill_size_a )
{
  *ifill_size_a = antGlobal_c->binfo.idiag_size;
  if (*ifill_size_a>ibuf_size_a) *ifill_size_a = ibuf_size_a;

  memmove( sbuffer_a, (void *)antGlobal_c->binfo.sbite_diagnostic, *ifill_size_a );

  /* Clear the diagnostic buffer
   */
  antGlobal_c->binfo.idiag_size = 0;
}
