/***********************************************************/
/*                                                         */
/* File        : rockmfarm.c                               */
/* Description : ROCKM farm frame specific library         */
/*                                                         */
/* Author: Sfiligoi Igor                                   */
/*                                                         */
/* Created      : 07.07.1997                               */
/* Recreated    : 29.08.1997                               */
/* Last modified: 29.08.1997                               */
/*                                                         */
/***********************************************************/

#include <Error.h>

#include <RockM.h>
#include "rockmfarm.h"

/*****************************************************************/
/*                                                               */
/* Convert data comming from the collector in a format           */
/* suitable for further processing                               */
/*                                                               */
/* Do nothing if length==8                                       */
/*                                                               */
/* Collector format:                                             */
/*     unsigned int length (in bytes, including the length)      */
/*     unsigned int event_number                                 */
/*     data from the rockm without superheader and superfooter   */
/*                                                               */
/* New format:                                                   */
/*     unsigned int length (same as before)                      */
/*     unsigned int event_number  (same as before)               */
/*     array of all the slave words in the input data, with      */
/*                  the following format:                        */
/*                    5 bits: Chain_nr                           */
/*                    3 bits: Crate_addr                         */
/*                    4 bits: Slave_addr                         */
/*                    7 bits: Channel_addr                       */
/*               (1+12) bits: slave_data                         */
/*     last uint of the struct (length-4) contains length        */
/*          of the array                                         */
/*                                                               */
/* Returns :ROCKM_ERROR_FARM_OK in case of success            */
/*                                                               */
/*****************************************************************/

int rockm_farm_compact(unsigned int chain_nr,  /* Chain number, will be truncated to 5 bits (no check) */
		       unsigned int chan_mask, /* mask to be applied to the channel field */
		       unsigned int *data)     /* IN  : data comming from the collector
						  OUT : data in the new format */
{
  RockM_Sub_header_union  	sub_header; 
  RockM_Data_header_union  	data_header;
  unsigned int event_nr;
  unsigned int trigger_nr;
  unsigned int in_length;  /* in elements */
  unsigned int out_length; /* in elements, including event_nr */
  unsigned int scrd_mask;   /* slot, chan, res, data mask */

  /* prepare the scrd mask */
  scrd_mask = ((chan_mask&0x7f)<<13) | 0xf01fff;

  if (data[0]<8)
    {
      ErrorSetF(ROCKM_ERROR_FARM_UNKNOWN,"rockm_farm_compact","Invalid length! (%i)",data[0]);
      return ROCKM_ERROR_FARM_UNKNOWN;
    }

  if (data[0]==8)
    return ROCKM_ERROR_FARM_OK; /* if no data, exit immediately */

  /* truncate to 5 bits */
  chain_nr &= 0x1f;

  /* save input length and event_nr */
  in_length = data[0]/sizeof(unsigned int);
  event_nr = data[1];
  trigger_nr = event_nr & 0xfff;
 
  /* init out_length */
  out_length = 2; /* at least event_nr and length must be present */

  {
    int i;
    
    for (i=2; i<in_length; i++)
      {
	unsigned int softparity;
	
	/* subheader */
	
	SUB_HEADER = data[i];
	
	if (TYPE_h!=5)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SUBHEADER,"rockm_farm_compact","%i: Subheader expected.",i);
	    return ROCKM_ERROR_FARM_SUBHEADER;
	  }
	if (CRT_ADD_h!=CRATE)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SUBHEADER,"rockm_farm_compact","%i: Subheader crate address error (%i,%i).",i,CRT_ADD_h,CRATE);
	    return ROCKM_ERROR_FARM_SUBHEADER;
	  }
	if (T_WORD_h!=trigger_nr)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SUBHEADER,"rockm_farm_compact","%i: Subheader trigger error (%i,%i).",i,T_WORD_h,trigger_nr);
	    return ROCKM_ERROR_FARM_SUBHEADER;
	  }
	
	softparity = PARITY_h;
	
	i++;
	if (i>=in_length)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_UNKNOWN,"rockm_farm_compact","%i: Unexpected end of data.",i);
	    return ROCKM_ERROR_FARM_UNKNOWN;
	  }
	
	DATA_HEADER = data[i];
	
	/* at least one slave must be present */
	if (TYPE_D!=7)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SLAVE,"rockm_farm_compact","%i: Slave expected.",i);
            printf ("type_d %d data[i] %x\n", TYPE_D, data[i]);
	    return ROCKM_ERROR_FARM_SLAVE;
	  }
	
	while (TYPE_D!=6) /* subframe */
	  {
	    if (TYPE_D!=7)
	      {
		ErrorSetF(ROCKM_ERROR_FARM_SLAVE,"rockm_farm_compact","%i: Slave expected.",i);
            printf ("type_d %d data[i] %x\n", TYPE_D, data[i]);
		return ROCKM_ERROR_FARM_SLAVE;
	      }
	    
	    if (CRT_ADD_h!=CRT_ADD_D)
	      {
		ErrorSetF(ROCKM_ERROR_FARM_SLAVE,"rockm_farm_compact","%i: Slave crate address error (%i,%i).",i,CRT_ADD_h,CRT_ADD_D);
		return ROCKM_ERROR_FARM_SLAVE;
	      }
	    softparity ^= PARITY_D;
	    
	    /* write the header */
	    data[out_length] = ((DATA_HEADER & scrd_mask) | 
				((DATA_HEADER & 0x70000000)>>4) |
				(chain_nr<<27));
	    out_length++;
	    i++;
	    
	    DATA_HEADER = data[i];
	  }

	/* to speedup (one copy less), use the DATA_HEADER for subfooter */
	if (CRT_ADD_h!=CRT_ADD_D)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SUBFOOTER,"rockm_farm_compact","%i: Subfooter crate address error (%i,%i).",i,CRT_ADD_h,CRT_ADD_D);
	    return ROCKM_ERROR_FARM_SUBFOOTER;
	  }

	if (softparity!=PARITY_D)
	  {
	    ErrorSetF(ROCKM_ERROR_FARM_SUBFOOTER,"rockm_farm_compact","%i: Subfooter parity error (%i,%i).",i,softparity,PARITY_D);
	    return ROCKM_ERROR_FARM_SUBFOOTER;
	  }
      }
  }


  data[in_length-1] = (out_length-2)*sizeof(unsigned int);

  return ROCKM_ERROR_FARM_OK;
}