/************************************************/
/*                                              */
/* File        : rockfifo.c                     */
/* Description : ROCK FIFO specific library     */
/*                                              */
/* Author: Sfiligoi Igor                        */
/*                                              */
/* Comment: If this module is used,             */
/*          nobody else should access the FIFO  */
/*                                              */
/* Created      : 14.02.1997                    */
/* Last modified: 07.04.1997                    */
/*                                              */
/************************************************/

#include <stdlib.h>
#include <Error.h>

#include "rockfifo.h"
#include "rockframes.h"

#include "rockfifo_private.h"

/**********************************************************************/
/*                                                                    */
/*                       Initialisation routines                      */
/*                                                                    */
/**********************************************************************/

int rock_fifo_open(ROCK_id       rock_id,   /* IN : standard rock id */
		   unsigned char fifotype,  /* IN : ROCK_FIFO_EFIFO or ROCK_FIFO_DFIFO */
		   unsigned char cancache,  /* IN : see ROCK_FIFO_CACHE_... constants */
                   ROCK_FIFO_id *fifo_id)   /* OUT: fifo id related to the rock */
{
 (*fifo_id) = (ROCK_FIFO_id_base *) malloc(sizeof(ROCK_FIFO_id_base));
 if ((*fifo_id)==NULL)
   { /* malloc error */
     ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_open","Malloc returned NULL.");
     return ROCK_ERROR_UNKNOWN;
   }

 (*fifo_id)->rock_id = rock_id;
 (*fifo_id)->head = 0;
 (*fifo_id)->tail = 0;
 (*fifo_id)->fifotype = fifotype;

 (*fifo_id)->cancache = ROCK_FIFO_CACHE_OFF;
 return rock_fifo_set_cancache((*fifo_id),cancache);
}


int rock_fifo_close(ROCK_FIFO_id   fifo_id,      /* IN : fifo id */
                    ROCK_FIFO_RAW_bits *cache)   /* OUT: the unused cache */
					         /*      should be disposed by caller */ 
{
 cache->nrels=rock_fifo_cache_get_nrels(fifo_id);

 if (cache->nrels!=0)
   {
     cache->els = (ROCK_EDFIFO_bits *) malloc(cache->nrels*sizeof(ROCK_EDFIFO_bits));
     if (cache->els==NULL)
       { /* malloc error */
	 ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_close","Malloc returned NULL.");
	 return ROCK_ERROR_UNKNOWN;
       }

     rock_fifo_cache_read_bits(fifo_id,cache->nrels,cache->els);
   }
 else
   cache->els = NULL;

 free(fifo_id);

 return ROCK_ERROR_OK;
}		    

/**********************************************************************/
/*                                                                    */
/*                          Settings routines                         */
/*                                                                    */
/**********************************************************************/

int rock_fifo_set_cancache(ROCK_FIFO_id  fifo_id,	/* IN : fifo id */
			   unsigned char cancache)	/* IN : new cancache value */
{
 fifo_id->cancache = cancache;

 return ROCK_ERROR_OK;
}

/**********************************************************************/
/*                                                                    */
/*                          Cache routines                            */
/*                                                                    */
/**********************************************************************/

int rock_fifo_cache_flush(ROCK_FIFO_id   fifo_id,	/* IN : fifo id */
			  ROCK_FIFO_RAW_bits *cache)   	/* OUT: the unused cache */
							/*      should be disposed by caller */ 
{
 cache->nrels=rock_fifo_cache_get_nrels(fifo_id);
 if (cache->nrels!=0)
   {
     cache->els = (ROCK_EDFIFO_bits *) malloc(cache->nrels*sizeof(ROCK_EDFIFO_bits));
     if (cache->els==NULL)
       { /* malloc error */
	 ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_cache_flush","Malloc returned NULL.");
	 return ROCK_ERROR_UNKNOWN;
       }
     
     rock_fifo_cache_read_bits(fifo_id,cache->nrels,cache->els);
   }
 else
   cache->els = NULL;

 return ROCK_ERROR_OK;
}		    

    /* Very dangerous!!!! */
int rock_fifo_cache_refill_bits(ROCK_FIFO_id  fifo_id,   /* IN : fifo_id */
                                ROCK_FIFO_RAW_bits data) /* IN : data to be filled to the cache */
{
 return rock_fifo_cache_return_bits(fifo_id,data.els,data.nrels);
}

/**********************************************************************/
/*                                                                    */
/*                          Raw read routines                         */
/*                                                                    */
/**********************************************************************/

int rock_fifo_raw_read(ROCK_FIFO_id  fifo_id,		/* IN : fifo id */
		       unsigned int *data)		/* OUT: one FIFO value */
{
 int err;

 err = rock_fifo_cache_read(fifo_id,1,data);
 if (err==ROCK_ERROR_OK)
   return ROCK_ERROR_OK;   /* was in cache, ok */

 err = rock_fifo_fillcache(fifo_id,1);

 if (err==ROCK_ERROR_OK)
   { /* data is in cache => read from cache */
     rock_fifo_cache_read(fifo_id,1,data);
     return ROCK_ERROR_OK;
   }
 else if (err==ROCK_ERROR_FIFO_EMPTY)
   return err;
 else
   { /* serious error */
     ErrorSetF(err,"rock_fifo_raw_read","rock_fifo_fillcache error: %s",ErrorGetMessage());
     return err;
   }

}

int rock_fifo_raw_blockread(ROCK_FIFO_id   fifo_id,	/* IN : fifo id */
			    unsigned int   nrels,	/* IN : max number of elements */
			    ROCK_FIFO_RAW *data)	/* OUT: FIFO data */
					    		/*      should be disposed by caller */ 
{
 int csize;
 unsigned int *actel;         /* point to the first unused space in data->els */
 int err;

 data->els = (unsigned int *) malloc(nrels*sizeof(unsigned int));
 if (data->els==NULL)
   { /* malloc error */
     ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_raw_blockread","Malloc returned NULL.");
     return ROCK_ERROR_UNKNOWN;
   }

 actel = data->els;
 data->nrels=0;

 while (1)
   {
     csize = rock_fifo_cache_get_nrels(fifo_id);
     if (csize>=nrels)
       { /* all needed elements are in cache */
	 data->nrels+=nrels;
	 rock_fifo_cache_read(fifo_id,nrels,actel);
	 return ROCK_ERROR_OK;
       }
     
     /* cache has not enough elements */
     data->nrels+=csize;
     rock_fifo_cache_read(fifo_id,csize,actel);
     
     /* loop */
     nrels-=csize;
     
     err = rock_fifo_fillcache(fifo_id,nrels);

     if (err!=ROCK_ERROR_OK)
       {
	 if (err!=ROCK_ERROR_FIFO_EMPTY)
	   { /* serious error, exit */
	     ErrorSetF(err,"rock_fifo_raw_blockread","rock_fifo_fillcache error: %s",ErrorGetMessage());
	     return err;
	   }
	 else
	   { /* save the elements found and exit*/
	     csize = rock_fifo_cache_get_nrels(fifo_id);
	     data->nrels+=csize;
	     rock_fifo_cache_read(fifo_id,csize,actel);
	     return ROCK_ERROR_FIFO_EMPTY;
	   }
       }
   }
}

/**********************************************************************/
/*                                                                    */
/*                    Complete raw read routines                      */
/*                                                                    */
/**********************************************************************/

int rock_fifo_raw_read_bits(ROCK_FIFO_id  fifo_id,		/* IN : fifo id */
			    ROCK_EDFIFO_bits *data)		/* OUT: one FIFO value */
{
 int err;

 err = rock_fifo_cache_read_bits(fifo_id,1,data);
 if (err==ROCK_ERROR_OK)
   return ROCK_ERROR_OK;   /* was in cache, ok */

 err = rock_fifo_fillcache(fifo_id,1);

 if (err==ROCK_ERROR_OK)
   { /* data is in cache => read from cache */
     rock_fifo_cache_read_bits(fifo_id,1,data);
     return ROCK_ERROR_OK;
   }
 else if (err==ROCK_ERROR_FIFO_EMPTY)
   return err;
 else
   { /* serious error */
     ErrorSetF(err,"rock_fifo_raw_read_bits","rock_fifo_fillcache error: %s",ErrorGetMessage());
     return err;
   }

}

int rock_fifo_raw_blockread_bits(ROCK_FIFO_id   fifo_id,	/* IN : fifo id */
				 unsigned int   nrels,		/* IN : max number of elements */
				 ROCK_FIFO_RAW_bits *data)	/* OUT: FIFO data */
					    			/*      should be disposed by caller */ 
{
 int csize;
 ROCK_EDFIFO_bits *actel;         /* point to the first unused space in data->els */
 int err;

 data->els = (ROCK_EDFIFO_bits *) malloc(nrels*sizeof(ROCK_EDFIFO_bits));
 if (data->els==NULL)
   { /* malloc error */
     ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_raw_blockread_bits","Malloc returned NULL.");
     return ROCK_ERROR_UNKNOWN;
   }

 actel = data->els;
 data->nrels=0;

 while (1)
   {
     csize = rock_fifo_cache_get_nrels(fifo_id);
     if (csize>=nrels)
       { /* all needed elements are in cache */
	 data->nrels+=nrels;
	 rock_fifo_cache_read_bits(fifo_id,nrels,actel);
	 return ROCK_ERROR_OK;
       }
     
     /* cache has not enough elements */
     data->nrels+=csize;
     rock_fifo_cache_read_bits(fifo_id,csize,actel);
     
     /* loop */
     nrels-=csize;
     
     err = rock_fifo_fillcache(fifo_id,nrels);

     if (err!=ROCK_ERROR_OK)
       {
	 if (err!=ROCK_ERROR_FIFO_EMPTY)
	   { /* serious error, exit */
	     ErrorSetF(err,"rock_fifo_raw_blockread_bits","rock_fifo_fillcache error: %s",ErrorGetMessage());
	     return err;
	   }
	 else
	   { /* save the elements found and exit*/
	     csize = rock_fifo_cache_get_nrels(fifo_id);
	     data->nrels+=csize;
	     rock_fifo_cache_read_bits(fifo_id,csize,actel);
	     return ROCK_ERROR_FIFO_EMPTY;
	   }
       }
   }
}

/**********************************************************************/
/*                                                                    */
/*                          Frame read routines                       */
/*                                                                    */
/**********************************************************************/

int rock_fifo_frame_read(ROCK_FIFO_id     fifo_id,	/* IN : fifo id */
		   	 ROCK_FIFO_FRAME *data) 	/* OUT: one FIFO value */
{
 int nrels;
 ROCK_EDFIFO_bits rawels[ROCK_FIFO_FRAME_SIZE];
 unsigned int softparity;
 unsigned char prec_addr;       /* needed to test that addresses go from highest to lower */
 unsigned int nrslaves[16];     /* nr of slaves with a address are in the frame */

 int err,whatis;

 /* read header */
 err = rock_fifo_raw_read_bits(fifo_id,&(rawels[0]));

   /* exit immediatly if cannot read the header */
 if (err!=ROCK_ERROR_OK)
   if (err==ROCK_ERROR_FIFO_EMPTY)
     return err;
   else
     {
       ErrorSetF(err,"rock_fifo_frame_read","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
       return err;
     }

 whatis= rockf_whatis(rawels[0].fifodata);
 if (whatis==ROCKF_IS_EMPTY)
   {  /* set the frame and exit */
     ROCKF_EMPTY_bits empty;
     int i;
     
     rockf_nr2empty(rawels[0].fifodata,empty);
     data->header.sy = empty.sy;
     data->header.last = empty.l;
     data->header.cradd = empty.ca;
     data->header.trigger = empty.trigger;
     data->footer.last = empty.l;
     data->footer.softparity = empty.parity;
     data->footer.hardparity = empty.parity;
     
     for (i=0; i<16; i++)
       {
	 data->slv[i].nrels = 0;
	 data->slv[i].els = NULL;
       }

    return ROCK_ERROR_OK;
   }
 else if (whatis!=ROCKF_IS_HEADER)
   { /* error, return element to cache and report error */
    rock_fifo_cache_return_bits(fifo_id,rawels,1);
    ErrorSetF(ROCK_ERROR_FIFO_FRAME_HEADER,"rock_fifo_frame_read","Header expected.");
    return ROCK_ERROR_FIFO_FRAME_HEADER;
   }

 /* header data will be saved after the full frame read */

 /* Now I have the header, start reading slaves */
 prec_addr = 255;
 {
   int i;
   for (i=0; i<16; i++)
     nrslaves[i]=0;
 }
 {
   int i;

   for (i=1; i<ROCK_FIFO_FRAME_SIZE; i++)
     {
       ROCKF_SLAVE_bits slave;

       err = rock_fifo_raw_read_bits(fifo_id,&(rawels[i]));

       /* exit if cannot read the FIFO */
       if (err!=ROCK_ERROR_OK)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i);
	   if (err!=ROCK_ERROR_FIFO_EMPTY)
	     ErrorSetF(err,"rock_fifo_frame_read","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
	   return err;
	 }

       whatis= rockf_whatis(rawels[i].fifodata);
       if (whatis==ROCKF_IS_FOOTER)
	 break;    /* exit from loop and elaborate footer */
       else if (whatis!=ROCKF_IS_SLAVE)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_read","A header before a footer found.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       /* interpret the slave */

       rockf_nr2slave(rawels[i].fifodata,slave);

       if (slave.slvadd>prec_addr)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_read","Addresses not in decreasing order.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       prec_addr = slave.slvadd;
       nrslaves[slave.slvadd]++;
       /* data will be saved after the full frame read */
     }
 
  if (i>=ROCK_FIFO_FRAME_SIZE)
    { /* error, return elements to cache and report error */
      rock_fifo_cache_return_bits(fifo_id,rawels,ROCK_FIFO_FRAME_SIZE);
      ErrorSetF(ROCK_ERROR_FIFO_FRAME_OVERFLOW,"rock_fifo_frame_read","Frame too large.");
      return ROCK_ERROR_FIFO_FRAME_OVERFLOW;
    }

  nrels=i+1;
 }

 if (nrels==2)
   { /* a header followed by a footer not allowed */
     rock_fifo_cache_return_bits(fifo_id,rawels,nrels);
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_FOOTER,"rock_fifo_frame_read","Footer immediatly after header.");
     return ROCK_ERROR_FIFO_FRAME_FOOTER;
   }

 /* set the header */
 {
   ROCKF_HEADER_bits header;
   
   rockf_nr2header(rawels[0].fifodata,header);
   data->header.sy = header.sy;
   data->header.last = header.l;
   data->header.cradd = header.ca;
   data->header.trigger = header.trigger;
   
   softparity = header.parity;
 }
 
 /* set the slaves */
 {
   int i;

   /* allocate space */
   for (i=0; i<16; i++)
     {
       data->slv[i].nrels = 0;
       if (nrslaves[i]!=0)
	 {
	   data->slv[i].els = (ROCK_FIFO_SLV_data *) malloc(nrslaves[i]*sizeof(ROCK_FIFO_SLV_data));
	   if (data->slv[i].els==NULL)
	     { /* malloc error */
	       ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_read","Malloc returned NULL.");
	       return ROCK_ERROR_UNKNOWN;
	     }
	 }
       else
	 data->slv[i].els = NULL;

     }
   
   /* save data */
   for (i=1; i<(nrels-1); i++)
     {
       ROCKF_SLAVE_bits slave;
       int a_nrels;
       ROCK_FIFO_SLV_data *a_el;  /* element to write in */

       rockf_nr2slave(rawels[i].fifodata,slave);
       a_nrels = data->slv[slave.slvadd].nrels++;
       a_el = &(data->slv[slave.slvadd].els[a_nrels]);

       a_el->channel = slave.channel;
       a_el->reserved = slave.reserved;
       a_el->data = slave.data;

       softparity ^= slave.parity;
     }
 }

 /*Set footer */
 {
   ROCKF_FOOTER_bits footer;

   rockf_nr2footer(rawels[nrels-1].fifodata,footer);
   data->footer.last = footer.l;
   data->footer.hardparity = footer.parity;
   data->footer.softparity = softparity;
 }

 if (data->footer.hardparity!=data->footer.softparity)
   { /* report error, but do return the frame */
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_PARITY,"rock_fifo_frame_read","Parity error: hard %i soft %i.",
	       data->footer.hardparity,data->footer.softparity);
     return ROCK_ERROR_FIFO_FRAME_PARITY;
   }
 else
   return ROCK_ERROR_OK;
}

	/* parity error is not considered an error */
int rock_fifo_frame_blockread(ROCK_FIFO_id      fifo_id,/* IN : fifo id */
			      unsigned int      nrels,	/* IN : max number of raw elements */
			      ROCK_FIFO_FRAMEs *data)	/* OUT: FIFO data */
					    		/*      should be disposed by caller */ 
{
  int i;
  int err;

  if (nrels==0)
    { /* nothing to do */
      data->nrframes = 0;
      data->frames = NULL;
      return ROCK_ERROR_OK;
    }

  /* alloc space for the worst case */
  data->frames = (ROCK_FIFO_FRAME *) malloc(nrels*sizeof(ROCK_FIFO_FRAME));
  if (data->frames==NULL)
    { /* malloc error */
      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_blockread","Malloc returned NULL.");
      return ROCK_ERROR_UNKNOWN;
    }


  for (i=0; i<nrels; i++)
    {
      err = rock_fifo_frame_read(fifo_id,&(data->frames[i]));

      if ((err!=ROCK_ERROR_OK)&&(err!=ROCK_ERROR_FIFO_FRAME_PARITY))
	{
	  if (err==ROCK_ERROR_FIFO_EMPTY)
	    break;
	  else
	    { /* a serious error occured, exit */
	      ErrorSetF(err,"rock_fifo_frame_blockread","rock_fifo_frame_read error: %s",ErrorGetMessage());
	      data->nrframes=i;
	      return err;
	    }
	}
	 
      ErrorClear(); /* clean any old error */   
    }

 data->nrframes=i;
 if (data->nrframes<nrels)
   return ROCK_ERROR_FIFO_EMPTY;
 else
   return ROCK_ERROR_OK;
}

int rock_fifo_frame_rawread(ROCK_FIFO_id     fifo_id,	/* IN : fifo id */
			    ROCK_FIFO_RAW *data) 	/* OUT: one FIFO value */
				       			/*      should be disposed by caller */ 
{
 int nrels;
 ROCK_EDFIFO_bits rawels[ROCK_FIFO_FRAME_SIZE];
 unsigned int softparity;
 unsigned char prec_addr;       /* needed to test that addresses go from highest to lower */

 int err,whatis;

 data->nrels=0;
 data->els = NULL;

 /* read header */
 err = rock_fifo_raw_read_bits(fifo_id,&(rawels[0]));

   /* exit immediatly if cannot read the header */
 if (err!=ROCK_ERROR_OK)
   if (err==ROCK_ERROR_FIFO_EMPTY)
     return err;
   else
     {
       ErrorSetF(err,"rock_fifo_frame_rawread","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
       return err;
     }

 whatis= rockf_whatis(rawels[0].fifodata);
 if (whatis==ROCKF_IS_EMPTY)
   {  /* set the frame and exit */

     data->nrels = 1;     
     data->els = (unsigned int *) malloc(sizeof(unsigned int));
     if (data->els==NULL)
       { /* malloc error */
	 ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_rawread","Malloc returned NULL.");
	 return ROCK_ERROR_UNKNOWN;
       }
     data->els[0] = rawels[0].fifodata;

    return ROCK_ERROR_OK;
   }
 else if (whatis!=ROCKF_IS_HEADER)
   { /* error, return element to cache and report error */
    rock_fifo_cache_return_bits(fifo_id,rawels,1);
    ErrorSetF(ROCK_ERROR_FIFO_FRAME_HEADER,"rock_fifo_frame_rawread","Header expected.");
    return ROCK_ERROR_FIFO_FRAME_HEADER;
   }

 /* Now I have the header, start reading slaves */
 prec_addr = 255;
 {
   int i;

   for (i=1; i<ROCK_FIFO_FRAME_SIZE; i++)
     {
       ROCKF_SLAVE_bits slave;

       err = rock_fifo_raw_read_bits(fifo_id,&(rawels[i]));

       /* exit if cannot read the FIFO */
       if (err!=ROCK_ERROR_OK)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i);
	   if (err!=ROCK_ERROR_FIFO_EMPTY)
	     ErrorSetF(err,"rock_fifo_frame_rawread","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
	   return err;
	 }

       whatis= rockf_whatis(rawels[i].fifodata);
       if (whatis==ROCKF_IS_FOOTER)
	 break;    /* exit from loop and elaborate footer */
       else if (whatis!=ROCKF_IS_SLAVE)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_rawread","A header before a footer found.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       /* interpret the slave */

       rockf_nr2slave(rawels[i].fifodata,slave);

       if (slave.slvadd>prec_addr)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_rawread","Addresses not in decreasing order.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       prec_addr = slave.slvadd;
     }
 
  if (i>=ROCK_FIFO_FRAME_SIZE)
    { /* error, return elements to cache and report error */
      rock_fifo_cache_return_bits(fifo_id,rawels,ROCK_FIFO_FRAME_SIZE);
      ErrorSetF(ROCK_ERROR_FIFO_FRAME_OVERFLOW,"rock_fifo_frame_rawread","Frame too large.");
      return ROCK_ERROR_FIFO_FRAME_OVERFLOW;
    }

  nrels=i+1;
 }

 if (nrels==2)
   { /* a header followed by a footer not allowed */
     rock_fifo_cache_return_bits(fifo_id,rawels,nrels);
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_FOOTER,"rock_fifo_frame_rawread","Footer immediatly after header.");
     return ROCK_ERROR_FIFO_FRAME_FOOTER;
   }

 /* save the data */
 {
  int i;
 
  data->nrels = nrels;
  data->els = (unsigned int *) malloc(nrels*sizeof(unsigned int));
  if (data->els==NULL)
    { /* malloc error */
      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_rawread","Malloc returned NULL.");
      return ROCK_ERROR_UNKNOWN;
    }
  for (i=0; i<nrels; i++)
    {
      data->els[i] = rawels[i].fifodata;
    }
 }

 /* calc the softparity */
 /* header */
 {
   ROCKF_HEADER_bits header;
   
   rockf_nr2header(rawels[0].fifodata,header);
   
   softparity = header.parity;
 }
 
 /* slaves */
 {
   int i;

   for (i=1; i<(nrels-1); i++)
     {
       ROCKF_SLAVE_bits slave;

       rockf_nr2slave(rawels[i].fifodata,slave);

       softparity ^= slave.parity;
     }
 }

 /* footer */
 {
   ROCKF_FOOTER_bits footer;

   rockf_nr2footer(rawels[nrels-1].fifodata,footer);

   if (footer.parity!=softparity)
     { /* report error, but do return the frame */
       ErrorSetF(ROCK_ERROR_FIFO_FRAME_PARITY,"rock_fifo_frame_rawread","Parity error: hard %i soft %i.",
		 footer.parity,softparity);
       return ROCK_ERROR_FIFO_FRAME_PARITY;
     }
   else
     return ROCK_ERROR_OK;
 }

}

int rock_fifo_frame_rawread_bits(ROCK_FIFO_id     fifo_id,	/* IN : fifo id */
				 ROCK_FIFO_RAW_bits *data) 	/* OUT: one FIFO value */
				       				/*      should be disposed by caller */ 
{
 int nrels;
 ROCK_EDFIFO_bits rawels[ROCK_FIFO_FRAME_SIZE];
 unsigned int softparity;
 unsigned char prec_addr;       /* needed to test that addresses go from highest to lower */

 int err,whatis;

 data->nrels=0;
 data->els = NULL;

 /* read header */
 err = rock_fifo_raw_read_bits(fifo_id,&(rawels[0]));

   /* exit immediatly if cannot read the header */
 if (err!=ROCK_ERROR_OK)
   if (err==ROCK_ERROR_FIFO_EMPTY)
     return err;
   else
     {
       ErrorSetF(err,"rock_fifo_frame_rawread_bits","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
       return err;
     }

 whatis= rockf_whatis(rawels[0].fifodata);
 if (whatis==ROCKF_IS_EMPTY)
   {  /* set the frame and exit */

     data->nrels = 1;     
     data->els = (ROCK_EDFIFO_bits *) malloc(sizeof(ROCK_EDFIFO_bits));
     if (data->els==NULL)
       { /* malloc error */
	 ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_rawread_bits","Malloc returned NULL.");
	 return ROCK_ERROR_UNKNOWN;
       }
     data->els[0] = rawels[0];

    return ROCK_ERROR_OK;
   }
 else if (whatis!=ROCKF_IS_HEADER)
   { /* error, return element to cache and report error */
    rock_fifo_cache_return_bits(fifo_id,rawels,1);
    ErrorSetF(ROCK_ERROR_FIFO_FRAME_HEADER,"rock_fifo_frame_rawread_bits","Header expected.");
    return ROCK_ERROR_FIFO_FRAME_HEADER;
   }

 /* Now I have the header, start reading slaves */
 prec_addr = 255;
 {
   int i;

   for (i=1; i<ROCK_FIFO_FRAME_SIZE; i++)
     {
       ROCKF_SLAVE_bits slave;

       err = rock_fifo_raw_read_bits(fifo_id,&(rawels[i]));

       /* exit if cannot read the FIFO */
       if (err!=ROCK_ERROR_OK)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i);
	   if (err!=ROCK_ERROR_FIFO_EMPTY)
	     ErrorSetF(err,"rock_fifo_frame_rawread_bits","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
	   return err;
	 }

       whatis= rockf_whatis(rawels[i].fifodata);
       if (whatis==ROCKF_IS_FOOTER)
	 break;    /* exit from loop and elaborate footer */
       else if (whatis!=ROCKF_IS_SLAVE)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_rawread_bits","A header before a footer found.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       /* interpret the slave */

       rockf_nr2slave(rawels[i].fifodata,slave);

       if (slave.slvadd>prec_addr)
	 { /* error, return elements to cache and report error */
	   rock_fifo_cache_return_bits(fifo_id,rawels,i+1);
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_frame_rawread_bits","Addresses not in decreasing order.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       prec_addr = slave.slvadd;
     }
 
  if (i>=ROCK_FIFO_FRAME_SIZE)
    { /* error, return elements to cache and report error */
      rock_fifo_cache_return_bits(fifo_id,rawels,ROCK_FIFO_FRAME_SIZE);
      ErrorSetF(ROCK_ERROR_FIFO_FRAME_OVERFLOW,"rock_fifo_frame_rawread_bits","Frame too large.");
      return ROCK_ERROR_FIFO_FRAME_OVERFLOW;
    }

  nrels=i+1;
 }

 if (nrels==2)
   { /* a header followed by a footer not allowed */
     rock_fifo_cache_return_bits(fifo_id,rawels,nrels);
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_FOOTER,"rock_fifo_frame_rawread_bits","Footer immediatly after header.");
     return ROCK_ERROR_FIFO_FRAME_FOOTER;
   }

 /* save the data */
 {
  int i;
 
  data->nrels = nrels;
  data->els = (ROCK_EDFIFO_bits *) malloc(nrels*sizeof(ROCK_EDFIFO_bits));
  if (data->els==NULL)
    { /* malloc error */
      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_rawread_bits","Malloc returned NULL.");
      return ROCK_ERROR_UNKNOWN;
    }
  for (i=0; i<nrels; i++)
    {
      data->els[i] = rawels[i];
    }
 }

 /* calc the softparity */
 /* header */
 {
   ROCKF_HEADER_bits header;
   
   rockf_nr2header(rawels[0].fifodata,header);
   
   softparity = header.parity;
 }
 
 /* slaves */
 {
   int i;

   for (i=1; i<(nrels-1); i++)
     {
       ROCKF_SLAVE_bits slave;

       rockf_nr2slave(rawels[i].fifodata,slave);

       softparity ^= slave.parity;
     }
 }

 /* footer */
 {
   ROCKF_FOOTER_bits footer;

   rockf_nr2footer(rawels[nrels-1].fifodata,footer);

   if (footer.parity!=softparity)
     { /* report error, but do return the frame */
       ErrorSetF(ROCK_ERROR_FIFO_FRAME_PARITY,"rock_fifo_frame_rawread_bits","Parity error: hard %i soft %i.",
		 footer.parity,softparity);
       return ROCK_ERROR_FIFO_FRAME_PARITY;
     }
   else
     return ROCK_ERROR_OK;
 }

}

	/* block of data allocated each time */
#define ROCK_FIFO_FS_BLOCK		1024

	/* Synch the FIFO to the start of the frame */
int rock_fifo_frame_synch(ROCK_FIFO_id   fifo_id,	/* IN : fifo id */
			  ROCK_FIFO_RAW *data)		/* OUT: FIFO data */
					    		/*      should be disposed by caller */ 
{
  int err;
  int actblock;		/* actual size of the buffer */

  data->nrels = 0;
  actblock = ROCK_FIFO_FS_BLOCK;
  data->els = (unsigned int *) malloc(actblock*sizeof(unsigned int));
  if (data->els==NULL)
    { /* malloc error */
      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_synch","Malloc returned NULL.");
      return ROCK_ERROR_UNKNOWN;
    }

  /* read the first element without checking the type */
  err = rock_fifo_raw_read(fifo_id,&(data->els[data->nrels]));
  if (err!=ROCK_ERROR_OK)
    {
      if (err!=ROCK_ERROR_FIFO_EMPTY)
	{ /* serious error */
	  ErrorSetF(err,"rock_fifo_frame_synch","rock_fifo_raw_read error: %s",ErrorGetMessage());
	  return err;
	}
      else
	return ROCK_ERROR_FIFO_EMPTY;
    }
  data->nrels++;

  while (1)
    {
      int whatis;
      ROCK_EDFIFO_bits bits;

      err = rock_fifo_raw_read_bits(fifo_id,&bits);
      if (err!=ROCK_ERROR_OK)
	{
	  if (err!=ROCK_ERROR_FIFO_EMPTY)
	    { /* serious error */
	      ErrorSetF(err,"rock_fifo_frame_synch","rock_fifo_raw_read error: %s",ErrorGetMessage());
	      return err;
	    }
	  else
	    return ROCK_ERROR_FIFO_EMPTY;
	}

      whatis = rockf_whatis(bits.fifodata);
      if ((whatis==ROCKF_IS_HEADER)||(whatis==ROCKF_IS_EMPTY))
	{ /* found, return to cache and exit */
	  rock_fifo_cache_return_bits(fifo_id,&bits,1);
	  return ROCK_ERROR_OK;
	}

      /* not yet syncronised */
      data->els[data->nrels] = bits.fifodata;
      data->nrels++;
      if (data->nrels>=actblock)
	{ /* must resize the buffer */
	  actblock += ROCK_FIFO_FS_BLOCK;
	  data->els = (unsigned int *) realloc(data->els,actblock*sizeof(unsigned int));
	  if (data->els==NULL)
	    { /* realloc error */
	      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_synch","Realloc returned NULL.");
	      return ROCK_ERROR_UNKNOWN;
	    }
	}
    }
}

	/* Synch the FIFO to the start of the frame */
int rock_fifo_frame_synch_bits(ROCK_FIFO_id   fifo_id,		/* IN : fifo id */
			       ROCK_FIFO_RAW_bits *data)    	/* OUT: FIFO data */
					    			/*      should be disposed by caller */ 
{
  int err;
  int actblock;		/* actual size of the buffer */

  data->nrels = 0;
  actblock = ROCK_FIFO_FS_BLOCK;
  data->els = (ROCK_EDFIFO_bits *) malloc(actblock*sizeof(ROCK_EDFIFO_bits));
  if (data->els==NULL)
    { /* malloc error */
      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_synch_bits","Malloc returned NULL.");
      return ROCK_ERROR_UNKNOWN;
    }

  /* read the first element without checking the type */
  err = rock_fifo_raw_read_bits(fifo_id,&(data->els[data->nrels]));
  if (err!=ROCK_ERROR_OK)
    {
      if (err!=ROCK_ERROR_FIFO_EMPTY)
	{ /* serious error */
	  ErrorSetF(err,"rock_fifo_frame_synch_bits","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
	  return err;
	}
      else
	return ROCK_ERROR_FIFO_EMPTY;
    }
  data->nrels++;

  while (1)
    {
      int whatis;

      err = rock_fifo_raw_read_bits(fifo_id,&(data->els[data->nrels]));
      if (err!=ROCK_ERROR_OK)
	{
	  if (err!=ROCK_ERROR_FIFO_EMPTY)
	    { /* serious error */
	      ErrorSetF(err,"rock_fifo_frame_synch_bits","rock_fifo_raw_read_bits error: %s",ErrorGetMessage());
	      return err;
	    }
	  else
	    return ROCK_ERROR_FIFO_EMPTY;
	}

      whatis = rockf_whatis(data->els[data->nrels].fifodata);
      if ((whatis==ROCKF_IS_HEADER)||(whatis==ROCKF_IS_EMPTY))
	{ /* found, return to cache and exit */
	  rock_fifo_cache_return_bits(fifo_id,&(data->els[data->nrels]),1);
	  return ROCK_ERROR_OK;
	}

      /* not yet syncronised */
      data->nrels++;
      if (data->nrels>=actblock)
	{ /* must resize the buffer */
	  actblock += ROCK_FIFO_FS_BLOCK;
	  data->els = (ROCK_EDFIFO_bits *) realloc(data->els,actblock*sizeof(ROCK_EDFIFO_bits));
	  if (data->els==NULL)
	    { /* realloc error */
	      ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_frame_synch_bits","Realloc returned NULL.");
	      return ROCK_ERROR_UNKNOWN;
	    }
	}
    }
}

/**********************************************************************/
/*                                                                    */
/*                       Frame conversion routines                    */
/*                                                                    */
/**********************************************************************/

int rock_fifo_conv_frame2raw(ROCK_FIFO_FRAME indata,	/* IN : formatted data */
			     ROCK_FIFO_RAW *outdata)	/* OUT: raw data */
{
 int nrslaves;

 /* find out the number of slaves */
 {
  int i;

  nrslaves=0;

  for (i=0; i<16; i++)
    {
      nrslaves+=indata.slv[i].nrels;
    }
 }

 if (nrslaves==0)
   { /* an empty frame */
     ROCKF_EMPTY_bits aempty;

     outdata->nrels = 1;
     outdata->els = (unsigned int *) malloc(sizeof(unsigned int));
     if (outdata->els==NULL)
       { /* malloc error */
	 ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_convframe2raw","Malloc returned NULL.");
	 return ROCK_ERROR_UNKNOWN;
       }

     aempty.sy = indata.header.sy;
     aempty.l = indata.header.last;
     aempty.ca = indata.header.cradd;
     aempty.trigger = indata.header.trigger;
     outdata->els[0] = rockf_empty2nr(aempty);

     return ROCK_ERROR_OK;
   }

 /* not empty */
 outdata->nrels = nrslaves+2;
 outdata->els = (unsigned int *) malloc(outdata->nrels*sizeof(unsigned int));
 if (outdata->els==NULL)
   { /* malloc error */
     ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_convframe2raw","Malloc returned NULL.");
     return ROCK_ERROR_UNKNOWN;
   }

 {
   ROCKF_HEADER_bits aheader;

   aheader.sy = indata.header.sy;
   aheader.l = indata.header.last;
   aheader.ca = indata.header.cradd;
   aheader.trigger = indata.header.trigger;
   outdata->els[0] = rockf_header2nr(aheader);
 }

 {
   int slvnr;
   int actel;
   
   actel=1;

   for (slvnr=15; slvnr>=0; slvnr--)
     {
       int i;
       
       for (i=0; i<indata.slv[slvnr].nrels; i++)
	 {
	   ROCKF_SLAVE_bits aslave;

	   aslave.slvadd = slvnr;
	   aslave.channel = indata.slv[slvnr].els[i].channel;
	   aslave.reserved = indata.slv[slvnr].els[i].reserved;
	   aslave.data = indata.slv[slvnr].els[i].data;
	   outdata->els[actel] = rockf_slave2nr(aslave);
	   actel++;
	 }
     }
 }
 
 {
   ROCKF_FOOTER_bits afooter;

   afooter.l = indata.footer.last;
   afooter.parity = indata.footer.hardparity;
   outdata->els[outdata->nrels-1] = rockf_footer2nr(afooter);
 }

 return ROCK_ERROR_OK;
}

int rock_fifo_conv_raw2frame(ROCK_FIFO_RAW     indata,	/* IN : raw data */
			     ROCK_FIFO_FRAME *outdata)	/* OUT: formated data */
{
 int nrels;
 unsigned int *rawels;
 unsigned int softparity;
 unsigned char prec_addr;       /* needed to test that addresses go from highest to lower */
 unsigned int nrslaves[16];     /* nr of slaves with a address are in the frame */

 int err,whatis;

 if (indata.nrels==0)
   return ROCK_ERROR_FIFO_EMPTY;

 rawels = indata.els;

 whatis= rockf_whatis(rawels[0]);
 if (whatis==ROCKF_IS_EMPTY)
   {  /* set the frame and exit */
     ROCKF_EMPTY_bits empty;
     int i;
     
     rockf_nr2empty(rawels[0],empty);
     outdata->header.sy = empty.sy;
     outdata->header.last = empty.l;
     outdata->header.cradd = empty.ca;
     outdata->header.trigger = empty.trigger;
     outdata->footer.last = empty.l;
     outdata->footer.softparity = empty.parity;
     outdata->footer.hardparity = empty.parity;
     
     for (i=0; i<16; i++)
       {
	 outdata->slv[i].nrels = 0;
	 outdata->slv[i].els = NULL;
       }

    return ROCK_ERROR_OK;
   }
 else if (whatis!=ROCKF_IS_HEADER)
   { /* error, return element to cache and report error */
    ErrorSetF(ROCK_ERROR_FIFO_FRAME_HEADER,"rock_fifo_conv_raw2frame","Header expected.");
    return ROCK_ERROR_FIFO_FRAME_HEADER;
   }

 /* header data will be saved after the full frame read */

 /* Now I have the header, start reading slaves */
 prec_addr = 255;
 {
   int i;
   for (i=0; i<16; i++)
     nrslaves[i]=0;
 }
 {
   int i;

   for (i=1; i<ROCK_FIFO_FRAME_SIZE; i++)
     {
       ROCKF_SLAVE_bits slave;

       if (indata.nrels<=i)
	 return ROCK_ERROR_FIFO_EMPTY;

       whatis= rockf_whatis(rawels[i]);
       if (whatis==ROCKF_IS_FOOTER)
	 break;    /* exit from loop and elaborate footer */
       else if (whatis!=ROCKF_IS_SLAVE)
	 { /* error, return elements to cache and report error */
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_conv_raw2frame","A header before a footer found.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       /* interpret the slave */

       rockf_nr2slave(rawels[i],slave);

       if (slave.slvadd>prec_addr)
	 { /* error, return elements to cache and report error */
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_conv_raw2frame","Addresses not in decreasing order.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       prec_addr = slave.slvadd;
       nrslaves[slave.slvadd]++;
       /* data will be saved after the full frame read */
     }
 
  nrels=i+1;
 }

 if (nrels==2)
   { /* a header followed by a footer not allowed */
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_FOOTER,"rock_fifo_conv_raw2frame","Footer immediatly after header.");
     return ROCK_ERROR_FIFO_FRAME_FOOTER;
   }

 /* set the header */
 {
   ROCKF_HEADER_bits header;
   
   rockf_nr2header(rawels[0],header);
   outdata->header.sy = header.sy;
   outdata->header.last = header.l;
   outdata->header.cradd = header.ca;
   outdata->header.trigger = header.trigger;
   
   softparity = header.parity;
 }
 
 /* set the slaves */
 {
   int i;

   /* allocate space */
   for (i=0; i<16; i++)
     {
       outdata->slv[i].nrels = 0;
       if (nrslaves[i]!=0)
	 {
	   outdata->slv[i].els = (ROCK_FIFO_SLV_data *) malloc(nrslaves[i]*sizeof(ROCK_FIFO_SLV_data));
	   if (outdata->slv[i].els==NULL)
	     { /* malloc error */
	       ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_conv_raw2frame","Malloc returned NULL.");
	       return ROCK_ERROR_UNKNOWN;
	     }
	 }
       else
	 outdata->slv[i].els = NULL;

     }
   
   /* save data */
   for (i=1; i<(nrels-1); i++)
     {
       ROCKF_SLAVE_bits slave;
       int a_nrels;
       ROCK_FIFO_SLV_data *a_el;  /* element to write in */

       rockf_nr2slave(rawels[i],slave);
       a_nrels = outdata->slv[slave.slvadd].nrels++;
       a_el = &(outdata->slv[slave.slvadd].els[a_nrels]);

       a_el->channel = slave.channel;
       a_el->reserved = slave.reserved;
       a_el->data = slave.data;

       softparity ^= slave.parity;
     }
 }

 /*Set footer */
 {
   ROCKF_FOOTER_bits footer;

   rockf_nr2footer(rawels[nrels-1],footer);
   outdata->footer.last = footer.l;
   outdata->footer.hardparity = footer.parity;
   outdata->footer.softparity = softparity;
 }

 if (outdata->footer.hardparity!=outdata->footer.softparity)
   { /* report error, but do return the frame */
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_PARITY,"rock_fifo_conv_raw2frame","Parity error: hard %i soft %i.",
	       outdata->footer.hardparity,outdata->footer.softparity);
     return ROCK_ERROR_FIFO_FRAME_PARITY;
   }
 else
   return ROCK_ERROR_OK;
}

int rock_fifo_conv_raw_bits2frame(ROCK_FIFO_RAW_bits indata,	/* IN : raw data */
			          ROCK_FIFO_FRAME   *outdata)	/* OUT: formated data */
{
 int nrels;
 ROCK_EDFIFO_bits *rawels;
 unsigned int softparity;
 unsigned char prec_addr;       /* needed to test that addresses go from highest to lower */
 unsigned int nrslaves[16];     /* nr of slaves with a address are in the frame */

 int err,whatis;

 if (indata.nrels==0)
   return ROCK_ERROR_FIFO_EMPTY;

 rawels = indata.els;

 whatis= rockf_whatis(rawels[0].fifodata);
 if (whatis==ROCKF_IS_EMPTY)
   {  /* set the frame and exit */
     ROCKF_EMPTY_bits empty;
     int i;
     
     rockf_nr2empty(rawels[0].fifodata,empty);
     outdata->header.sy = empty.sy;
     outdata->header.last = empty.l;
     outdata->header.cradd = empty.ca;
     outdata->header.trigger = empty.trigger;
     outdata->footer.last = empty.l;
     outdata->footer.softparity = empty.parity;
     outdata->footer.hardparity = empty.parity;
     
     for (i=0; i<16; i++)
       {
	 outdata->slv[i].nrels = 0;
	 outdata->slv[i].els = NULL;
       }

    return ROCK_ERROR_OK;
   }
 else if (whatis!=ROCKF_IS_HEADER)
   { /* error, return element to cache and report error */
    ErrorSetF(ROCK_ERROR_FIFO_FRAME_HEADER,"rock_fifo_conv_raw_bits2frame","Header expected.");
    return ROCK_ERROR_FIFO_FRAME_HEADER;
   }

 /* header data will be saved after the full frame read */

 /* Now I have the header, start reading slaves */
 prec_addr = 255;
 {
   int i;
   for (i=0; i<16; i++)
     nrslaves[i]=0;
 }
 {
   int i;

   for (i=1; i<ROCK_FIFO_FRAME_SIZE; i++)
     {
       ROCKF_SLAVE_bits slave;

       if (indata.nrels<=i)
	 return ROCK_ERROR_FIFO_EMPTY;

       whatis= rockf_whatis(rawels[i].fifodata);
       if (whatis==ROCKF_IS_FOOTER)
	 break;    /* exit from loop and elaborate footer */
       else if (whatis!=ROCKF_IS_SLAVE)
	 { /* error, return elements to cache and report error */
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_conv_raw_bits2frame","A header before a footer found.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       /* interpret the slave */

       rockf_nr2slave(rawels[i].fifodata,slave);

       if (slave.slvadd>prec_addr)
	 { /* error, return elements to cache and report error */
	   ErrorSetF(ROCK_ERROR_FIFO_FRAME_SLAVE,"rock_fifo_conv_raw_bits2frame","Addresses not in decreasing order.");
	   return ROCK_ERROR_FIFO_FRAME_SLAVE;
	 }

       prec_addr = slave.slvadd;
       nrslaves[slave.slvadd]++;
       /* data will be saved after the full frame read */
     }
 
  nrels=i+1;
 }

 if (nrels==2)
   { /* a header followed by a footer not allowed */
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_FOOTER,"rock_fifo_conv_raw_bits2frame","Footer immediatly after header.");
     return ROCK_ERROR_FIFO_FRAME_FOOTER;
   }

 /* set the header */
 {
   ROCKF_HEADER_bits header;
   
   rockf_nr2header(rawels[0].fifodata,header);
   outdata->header.sy = header.sy;
   outdata->header.last = header.l;
   outdata->header.cradd = header.ca;
   outdata->header.trigger = header.trigger;
   
   softparity = header.parity;
 }
 
 /* set the slaves */
 {
   int i;

   /* allocate space */
   for (i=0; i<16; i++)
     {
       outdata->slv[i].nrels = 0;
       if (nrslaves[i]!=0)
	 {
	   outdata->slv[i].els = (ROCK_FIFO_SLV_data *) malloc(nrslaves[i]*sizeof(ROCK_FIFO_SLV_data));
	   if (outdata->slv[i].els==NULL)
	     { /* malloc error */
	       ErrorSet(ROCK_ERROR_UNKNOWN,"rock_fifo_conv_raw_bits2frame","Malloc returned NULL.");
	       return ROCK_ERROR_UNKNOWN;
	     }
	 }
       else
	 outdata->slv[i].els = NULL;

     }
   
   /* save data */
   for (i=1; i<(nrels-1); i++)
     {
       ROCKF_SLAVE_bits slave;
       int a_nrels;
       ROCK_FIFO_SLV_data *a_el;  /* element to write in */

       rockf_nr2slave(rawels[i].fifodata,slave);
       a_nrels = outdata->slv[slave.slvadd].nrels++;
       a_el = &(outdata->slv[slave.slvadd].els[a_nrels]);

       a_el->channel = slave.channel;
       a_el->reserved = slave.reserved;
       a_el->data = slave.data;

       softparity ^= slave.parity;
     }
 }

 /*Set footer */
 {
   ROCKF_FOOTER_bits footer;

   rockf_nr2footer(rawels[nrels-1].fifodata,footer);
   outdata->footer.last = footer.l;
   outdata->footer.hardparity = footer.parity;
   outdata->footer.softparity = softparity;
 }

 if (outdata->footer.hardparity!=outdata->footer.softparity)
   { /* report error, but do return the frame */
     ErrorSetF(ROCK_ERROR_FIFO_FRAME_PARITY,"rock_fifo_conv_raw_bits2frame","Parity error: hard %i soft %i.",
	       outdata->footer.hardparity,outdata->footer.softparity);
     return ROCK_ERROR_FIFO_FRAME_PARITY;
   }
 else
   return ROCK_ERROR_OK;
}

/**********************************************************************/
/*                                                                    */
/*                          FIFO test routines                        */
/*                                                                    */
/**********************************************************************/

int rock_fifo_isnotempty(ROCK_FIFO_id fifo_id)	/* IN : fifo id */
{
 ROCKB_EDFIFO_bits flags;

 if (rock_fifo_cache_get_nrels(fifo_id)!=0)
   { /* if data is in cache, not empty */
     return ROCK_ERROR_OK;
   }

 rock_fifo_flags(fifo_id,&flags);
 if (flags.ef==0)
   return ROCK_ERROR_FIFO_EMPTY;
 else
   return ROCK_ERROR_OK;
}