/****************************************************************************
 *  F i l e   D a t a                                                        
 *  $Id: HB_HKBuffer_INFN.c,v 1.63 2005/03/13 18:11:41 sebastiani Exp $
 *  $Revision: 1.63 $ 
 *  $Date: 2005/03/13 18:11:41 $     
 *  $RCSfile: HB_HKBuffer_INFN.c,v $ 
 *                                                                           
 ****************************************************************************
 *  S W   D e v e l o p m e n t   E n v i r o n m e n t                      
 *                                                                           
 *  $Author: sebastiani $                                                                   
 ****************************************************************************
 *                                                                           
 *****************************************************************************/


/*============================= Include File ================================*/

#include <src/INFN/LU_SourceFileID_INFN.h>
#define __FILEID__ _HB_HKBuffer_INFN__c
#include <src/INFN/PRH_ParamHandler_INFN.h>
#include <src/INFN/LU_LogUtility_INFN.h>
#include <src/INFN/PRH_ParamHandler_INFN_auto.h>
#include <src/INFN/PRH_ParamHandler_INFN_autopri.h>
LU_DECL_MASK();

#include <src/FileManager/MMSUManager/FT_MMSUManager_p.h>
#include <src/INFN/HB_HKBuffer_INFN.h>
#include <src/SRAMManager/SRAMPageManager/SM_SRAMPageManager_p.h>
#include <src/TM_TCManager/TMTCManager/TM_TMTCManager_p.h>

/*============================ Global define ================================*/

#define HB_N_BUF_SIZE  1

#define HB_EOB_LEN        16
#define HB_HEADER_LEN     16


/* table or array selector. private use only */
#define HB_2TAB 1
#define HB_2ARR 2

/*============================== global types  ==============================*/

static BYTE _HB_TMTC[HB_BUF_TMTC_SIZE];
static BYTE _HB_LOG [HB_BUF_LOG_SIZE];
static BYTE _HB_MCMD[HB_BUF_MCMD_SIZE];
static BYTE _HB_SKETCHBOARD[HB_BUF_SKETCHBOARD_SIZE];
static BYTE _HB_MISC[HB_BUF_MISC_SIZE];
static BYTE _HB_TSB_T[HB_BUF_TSB_T_SIZE];
static BYTE _HB_TSB_B[HB_BUF_TSB_B_SIZE];
static BYTE _HB_USERDATA0[HB_BUF_USERDATA_SIZE];
static BYTE _HB_USERDATA1[HB_BUF_USERDATA_SIZE];
static BYTE _HB_USERDATA2[HB_BUF_USERDATA_SIZE];
static BYTE _HB_USERDATA3[HB_BUF_USERDATA_SIZE];
static BYTE _HB_RAW[HB_BUF_RAW_SIZE];

static DAQ_CMD_BUF HB_Buffer[HB_MAX];
static UINT32 HB_RecordsCounter[HB_MAX];
//static UINT32 HB_PktCounter[HB_MAX];
//static UINT32 PktCounter=0;
static UINT32 HB_PktType[HB_MAX];
static UINT32 HB_Flush_Request_Counter;

/* the writing is in BIG ENDIAN fascion */
#define HB_WRITE_UINT8(bufid,byte) do { \
  HB_Buffer[bufid].buf[HB_Buffer[bufid].len] = (unsigned char)(byte); \
  HB_Buffer[bufid].len++; \
} while(0)

#define HB_WRITE_UINT16(bufid,word) do { \
  HB_WRITE_UINT8(bufid,(unsigned char)((word)>>8)); \
  HB_WRITE_UINT8(bufid,(unsigned char)(word)); \
} while(0)

#define HB_WRITE_UINT32(bufid,dword) do { \
  HB_WRITE_UINT8(bufid,(unsigned char)((dword)>>24)); \
  HB_WRITE_UINT8(bufid,(unsigned char)((dword)>>16)); \
  HB_WRITE_UINT8(bufid,(unsigned char)((dword)>>8)); \
  HB_WRITE_UINT8(bufid,(unsigned char)(dword));      \
} while(0)

// returns the pointer to the first available byte in the buffer
#define HB_END_BYTE_PTR(bufid) (&(HB_Buffer[bufid].buf[HB_Buffer[bufid].len]))

#define HB_WRITE_MEMCPY(bufid,p,size) do { \
  UINT32 tmpsize=(size); /* the compiler should optimize this */ \
  memcpy(HB_END_BYTE_PTR(bufid),p,tmpsize); \
  HB_Buffer[bufid].len +=tmpsize;           \
} while(0)

#define HB_CTRL_INTERRUPT() do { \
 if(rtems_interrupt_is_in_progress()) \
   return CM_RC_INTERRUPT_IS_IN_PROGRESS; \
} while(0)



#define HB_IS_FULL_ENOUGH(bufid) (HB_Buffer[bufid].len>0)
#define HB_SPACE_LEFT(bufid) (HB_Buffer[bufid].size - HB_Buffer[bufid].len)
#define HB_BUFLEN(bufid) (HB_Buffer[bufid].len)
 
/*****************************************************************************/
/*=========================== Structure define ==============================*/


/*****************************************************************************/
/*============================ Enumerate define =============================*/

/*****************************************************************************/





/*****************************************************************************/


status_code HB_SemP() {
  status_code s;
  if((s=OS_piResourceObtain_INFN(HB_BUF_INFN_RES,RTEMS_WAIT,RTEMS_NO_TIMEOUT)) == SUCCESSFUL){
    LU_StoreInHB(FALSE);
    return CM_RC_SUCCESSFUL;
  }
  else {
    /*@LOG SemP: error - status */
    LU_INFN_LOG(LU_FATAL|LU_HA , LU_MASK(__FILEID__),__FILEID__,__LINE__,s);
    return CM_RC_RES_ERR;
  }  
}

status_code HB_SemV() {
  status_code s;
  LU_StoreInHB(TRUE);
  s=OS_piResourceRelease_INFN(HB_BUF_INFN_RES);
  if(s == SUCCESSFUL)
    return CM_RC_SUCCESSFUL;
  else {
    /*@LOG SemV: error - status */
    LU_INFN_LOG(LU_FATAL|LU_HA, LU_MASK(__FILEID__),__FILEID__,__LINE__,s);
    return CM_RC_RES_ERR;
  }
}

status_code HB_ResetFlushRequestCounter() {
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    HB_Flush_Request_Counter=0;
    HB_SemV();
    return CM_RC_SUCCESSFUL;
  }else
    return CM_RC_RES_ERR;
}

status_code HB_GetFlushRequestFlag(BOOL *b) {
  if(HB_SemP() == CM_RC_SUCCESSFUL && b!=NULL) {
    *b=HB_Flush_Request_Counter>0;
    HB_SemV();
    return CM_RC_SUCCESSFUL;

  }else
    return CM_RC_RES_ERR;
}

status_code HB_Init() {
  HB_BUF b;
  for(b=0;b<HB_MAX;b++) {
    HB_InitBuf_NoLock(b);
    //HB_PktCounter[b]=0;
  }
  HB_Flush_Request_Counter=0;

#define HB_setpt(id) HB_PktType[HB_##id]=HB_PKTTYPE_##id;
  HB_setpt(TMTC);
  HB_setpt(MCMD);
  HB_setpt(LOG);
  HB_setpt(TSB_T);
  HB_setpt(TSB_B);
  HB_setpt(VARDUMP);
  HB_setpt(ARRDUMP);
  HB_setpt(TABDUMP);
  HB_setpt(VAR);
  HB_setpt(ARR);
  HB_setpt(TAB);
#undef HB_setpt

  LU_StoreInHB(TRUE);
}

status_code HB_InitBuf_NoLock(HB_BUF bufid) {
  BYTE *buf;
  switch(bufid) {
  case HB_TMTC:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_TMTC],HB_BUF_TMTC_SIZE,0,_HB_TMTC);
    break;
  case HB_MCMD:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_MCMD],HB_BUF_MCMD_SIZE,0,_HB_MCMD);
    break;
  case HB_LOG:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_LOG],HB_BUF_LOG_SIZE,0,_HB_LOG);
    break;
  case HB_TSB_T:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_TSB_T],HB_BUF_TSB_T_SIZE,0,_HB_TSB_T);
    break;
  case HB_TSB_B:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_TSB_B],HB_BUF_TSB_B_SIZE,0,_HB_TSB_B);
    break;
  case HB_ARRDUMP:
  case HB_TABDUMP:
  case HB_VARDUMP:
  case HB_VAR:
  case HB_ARR:
  case HB_TAB:
    /* they are not really buffers */
    break;
  case HB_SKETCHBOARD:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_SKETCHBOARD],HB_BUF_SKETCHBOARD_SIZE,0,_HB_SKETCHBOARD);
    break;
  case HB_MISC:
    DAQ_Format_CMD_Init(&HB_Buffer[HB_MISC],HB_BUF_MISC_SIZE,0,_HB_MISC);
    break;
  case HB_USERDATA0:
    DAQ_Format_CMD_Init(&HB_Buffer[bufid],HB_BUF_USERDATA_SIZE,0,_HB_USERDATA0);
    break;
  case HB_USERDATA1:
    DAQ_Format_CMD_Init(&HB_Buffer[bufid],HB_BUF_USERDATA_SIZE,0,_HB_USERDATA1);
    break;
  case HB_USERDATA2:
    DAQ_Format_CMD_Init(&HB_Buffer[bufid],HB_BUF_USERDATA_SIZE,0,_HB_USERDATA2);
    break;
  case HB_USERDATA3:
    DAQ_Format_CMD_Init(&HB_Buffer[bufid],HB_BUF_USERDATA_SIZE,0,_HB_USERDATA3);
    break;
  case HB_RAW:
    DAQ_Format_CMD_Init(&HB_Buffer[bufid],HB_BUF_RAW_SIZE,0,_HB_RAW);
    break;
  defaul:
    /*@LOG Unknown buffer id - bufid */
    LU_INFN_LOG(LU_INTERNAL|LU_HA, LU_MASK(__FILEID__),__FILEID__,__LINE__,bufid);
    break;
  }
  HB_RecordsCounter[bufid]=0;
  return CM_RC_SUCCESSFUL;
}


status_code HB_InitBuf(HB_BUF bufid) {
  status_code s;
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    s=HB_InitBuf_NoLock(bufid);
    HB_SemV();
    return s;
  }else
    return CM_RC_RES_ERR;
}

unsigned int HB_SpaceLeft(HB_BUF bufid) {
  unsigned int v;
  HB_SemP();
  v = HB_Buffer[bufid].size - HB_Buffer[bufid].len;
  HB_SemV();
  return v;
}


status_code HB_WriteHeader(HB_BUF bufid,BYTE pkt_type,UINT32 len,TI_TIME obt) {
  return DAQ_WriteHeader2Buffer(&(HB_Buffer[bufid]),
			       PM_pi_GetAndIncrPckCnt(),
			       pkt_type,
			       len,
			       obt);
}



status_code HB_WriteHeader_Original(HB_BUF bufid,BYTE pkt_type,UINT32 len,TI_TIME obt) {
  UINT16 crc=0;
  UINT32 counter = PM_pi_GetAndIncrPckCnt();
  BYTE *start,b;
  if(HB_Buffer[bufid].size - HB_Buffer[bufid].len < 16) 
    return CM_RC_NO_SPACE_LEFT;
  // this shoud be not need: TI_piGetTimeInfo(&obt);
  start=HB_END_BYTE_PTR(bufid);

  HB_WRITE_UINT8(bufid,0xfa);
  HB_WRITE_UINT8(bufid,0xfe);
  HB_WRITE_UINT8(bufid,0xde);

  HB_WRITE_UINT8(bufid,pkt_type);
  HB_WRITE_UINT8(bufid,pkt_type);
  
  b=(counter>>16) & 0xff;
  HB_WRITE_UINT8(bufid,b);
  b=(counter>>8) & 0xff;
  HB_WRITE_UINT8(bufid,b);
  b=(counter & 0xff);
  HB_WRITE_UINT8(bufid,b);

  HB_WRITE_UINT32(bufid,obt);
  
  b=(len>>16) & 0xff;
  HB_WRITE_UINT8(bufid,b);
  b=(len>>8) & 0xff;
  HB_WRITE_UINT8(bufid,b);
  b=(len & 0xff);
  HB_WRITE_UINT8(bufid,b);

  crc = CM_Compute_CRC16(0,start,15);
  b=crc & 0xff;
  HB_WRITE_UINT8(bufid,b);
  return CM_RC_SUCCESSFUL;
}

status_code HB_StoreRaw(DAQ_CMD_BUF *b) {
  return HB_Store(HB_RAW,b->len,b->buf,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}

status_code HB_StoreMisc(BYTE pkttype,DAQ_CMD_BUF *b) {
  return HB_Store(HB_MISC,b->len,b->buf,HB_UNUSED,pkttype,HB_UNUSED);
}
status_code HB_StoreSketchboard() {
  return  HB_Store(HB_SKETCHBOARD,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreVarDump() {
  return HB_Store(HB_VARDUMP,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreArrDump() {
  return HB_Store(HB_ARRDUMP,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreTabDump() {
  return HB_Store(HB_TABDUMP,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreTMTC() {
  return HB_Store(HB_TMTC,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}

status_code HB_StoreVar(BYTE id) {
  return HB_Store(HB_VAR,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,id);
}
status_code HB_StoreArr(BYTE id) {
  return HB_Store(HB_ARR,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,id);
}
status_code HB_StoreTab(BYTE id) {
  return HB_Store(HB_TAB,HB_UNUSED,NULL,HB_UNUSED,HB_UNUSED,id);
}


status_code HB_StoreMcmd(MA_HEADER_MCMD* mcmd) {
  if(mcmd)
    return HB_Store(HB_MCMD,mcmd->Length*sizeof(UINT16),mcmd->PtrMCMD,
		    HB_UNUSED,HB_UNUSED,HB_UNUSED);
  else
    return CM_RC_NOINFO;
}
status_code HB_StoreUserData(BYTE bufno,UINT16 len,void *dataptr) {
  if(bufno >= HB_USERDATA_NO)
    return CM_RC_INVALID_BUFFER_ID;
  return HB_Store(HB_USERDATA0+bufno,len,dataptr,
		  HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreLog(UINT16 len,void *dataptr,TI_TIME obt) {
  return HB_Store(HB_LOG,len,dataptr,obt,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreTSB_T(DAQ_CMD_BUF *b) {
  return HB_Store(HB_TSB_T,b->len,b->buf,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}
status_code HB_StoreTSB_B(DAQ_CMD_BUF *b) {
  return HB_Store(HB_TSB_B,b->len,b->buf,HB_UNUSED,HB_UNUSED,HB_UNUSED);
}


// A buffer is considered "to be stored" if is at least (PRH_VAR_HB_ALMOST_FULL %) is filled up
void HB_IS_ALMOST_FULL(HB_BUF bufid) { 
  if(HB_Buffer[bufid].len  > (HB_Buffer[bufid].size * PRH_VAR_HB_ALMOST_FULL)/100) 
    HB_Flush_Request_Counter++; 
}


static status_code HB_Store(HB_BUF bufid,
			    unsigned short int len,void *dataptr,
			    TI_TIME obt,
			    BYTE miscpkttype,
			    UINT32 additional) {
  UINT32 i,size;
  status_code s=CM_RC_SUCCESSFUL;
  static UINT32 tmtc_tmp_array[TM_MAX_TELEMETRY];
  BYTE *buf=(BYTE*)dataptr;
  TI_TIME ts;
  PRH_VAR_TYPE var;
  PRH_VAR_TYPE *p;
  UINT16 crc;
  HB_BUF source;
  UINT32 dumplen;
  UINT32 tm_val,n,r,c,total_len;
  BYTE *start,*start_header, b,suppl;
  TM_TELEMETRY tm;
  BOOL mm;
  
  if(rtems_interrupt_is_in_progress())
    return CM_RC_INTERRUPT_IS_IN_PROGRESS;
  if(obt==HB_UNUSED)
    TI_piGetTimeInfo_ms(&obt);
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    switch(bufid) {
    case HB_RAW:
      if(HB_SPACE_LEFT(HB_RAW) < len)
	s=CM_RC_NO_SPACE_LEFT;
      else {
	HB_WRITE_MEMCPY(HB_RAW,buf,len);
	HB_RecordsCounter[HB_RAW]++;
      }
      break;
    case HB_VAR:
    case HB_ARR:
    case HB_TAB:
      i=additional;
      switch(bufid) {
      case HB_VAR:
	suppl=sizeof(BYTE) /* id */;
	PRH_int_get_var(i,&var);
	size=sizeof(PRH_VAR_TYPE);
	break;
      case HB_ARR:
	suppl=sizeof(BYTE) /* id */ + sizeof(UINT16) /* len */;
	PRH_int_get_arr_ptr(i,&p);
	PRH_int_get_arr_n(i,&n);
	PRH_SIZEOF_ARR(i,&size);
	break;
      case HB_TAB:
	suppl=sizeof(BYTE) /* id */ + sizeof(BYTE) /* row */ + sizeof(BYTE) /* cols */;
	PRH_int_get_tab_ptr(i,&p);
	PRH_int_get_tab_dim(i,&r,&c);
	PRH_SIZEOF_TABLE(i,&size);	
	break;
      }
      dumplen=size+suppl;
      if(HB_SPACE_LEFT(HB_SKETCHBOARD)
	 <
	 HB_HEADER_LEN   +  /* header */
	 dumplen        +  
	 sizeof(UINT16)     /* 2 byte crc 16 */
	 )
	s=CM_RC_NO_SPACE_LEFT;
      else {	
	HB_WriteHeader(HB_SKETCHBOARD,
		       HB_PktType[bufid],
		       dumplen+sizeof(UINT16),obt);
	start=HB_END_BYTE_PTR(HB_SKETCHBOARD);
	HB_WRITE_UINT8(HB_SKETCHBOARD,i);
	switch(bufid) {
	case HB_VAR:
	  HB_WRITE_UINT32(HB_SKETCHBOARD,var);
	  break;
	case HB_ARR:
	  HB_WRITE_UINT16(HB_SKETCHBOARD,n);
	  HB_WRITE_MEMCPY(HB_SKETCHBOARD,p,size);
	  break;
	case HB_TAB:
	  HB_WRITE_UINT8(HB_SKETCHBOARD,r);
	  HB_WRITE_UINT8(HB_SKETCHBOARD,c);
	  HB_WRITE_MEMCPY(HB_SKETCHBOARD,p,size);
	  break;
	}
	crc=CM_Compute_CRC16(0,start,dumplen);
	HB_WRITE_UINT16(HB_SKETCHBOARD,crc);
      }
      break;

    case HB_VARDUMP:
    case HB_ARRDUMP:
    case HB_TABDUMP:
      switch(bufid) {
      case HB_VARDUMP: 
	dumplen=PRH_get_var_dump_len();
	break;
      case HB_ARRDUMP:
	//dumplen=PRH_TOTAL_ARR_SIZE;
	dumplen=PRH_get_arr_dump_len();
	break;
      case HB_TABDUMP:
	//dumplen=PRH_TOTAL_TAB_SIZE;
	dumplen=PRH_get_tab_dump_len();
	break;
      default:
	{
	  HB_SemV();
	  return CM_RC_INTERNAL_ERR;
	}
      }
      if(HB_SPACE_LEFT(HB_SKETCHBOARD)
	 <
	 HB_HEADER_LEN   +  /* header */
	 sizeof(UINT32)  +  /* PRH_STAMP */
	 dumplen         +  /* len of dump */
	 sizeof(UINT16)     /* 2 byte crc 16 */
	 )
	s=CM_RC_NO_SPACE_LEFT;
      else {
	start_header=HB_END_BYTE_PTR(HB_SKETCHBOARD);
	HB_WriteHeader(HB_SKETCHBOARD,
		       HB_PktType[bufid],
		       dumplen+sizeof(UINT16)+sizeof(UINT32),obt);
	start=HB_END_BYTE_PTR(HB_SKETCHBOARD);
	HB_WRITE_UINT32(HB_SKETCHBOARD,PRH_STAMP);
	switch(bufid) {
	case HB_VARDUMP:
	  for(i=0;i<PRH_VAR_MAX;i++) {
	    if(PRH_int_var_is_in_mm(i,&mm) == CM_RC_SUCCESSFUL &&
	       mm &&
	       PRH_int_get_var(i,&var) == CM_RC_SUCCESSFUL) {
	      HB_WRITE_UINT8(HB_SKETCHBOARD,i);
	      HB_WRITE_UINT32(HB_SKETCHBOARD,var);
	    }
	  }
	  break;
	case HB_ARRDUMP:
	  for(i=0;i<PRH_ARR_MAX;i++) {
	    if(PRH_int_arr_is_in_mm(i,&mm) == CM_RC_SUCCESSFUL &&
	       mm &&
	       PRH_int_get_arr_ptr(i,&p) == CM_RC_SUCCESSFUL &&
	       PRH_int_get_arr_n(i,&n)   == CM_RC_SUCCESSFUL && 
	       PRH_SIZEOF_ARR(i,&size)   == CM_RC_SUCCESSFUL ) {
	      HB_WRITE_UINT8(HB_SKETCHBOARD,i);
	      HB_WRITE_UINT16(HB_SKETCHBOARD,n);
	      HB_WRITE_MEMCPY(HB_SKETCHBOARD,p,size);
	    }
	  }
	  break;
	case HB_TABDUMP:
	  for(i=0;i<PRH_TAB_MAX;i++) {
	    if(PRH_int_tab_is_in_mm(i,&mm) == CM_RC_SUCCESSFUL &&
	       mm &&
	       PRH_int_get_tab_ptr(i,&p) == CM_RC_SUCCESSFUL &&
	       PRH_int_get_tab_dim(i,&r,&c) == CM_RC_SUCCESSFUL &&
	       PRH_SIZEOF_TABLE(i,&size)   == CM_RC_SUCCESSFUL
	       ) {
	      HB_WRITE_UINT8(HB_SKETCHBOARD,i);
	      HB_WRITE_UINT8(HB_SKETCHBOARD,r);
	      HB_WRITE_UINT8(HB_SKETCHBOARD,c);
	      HB_WRITE_MEMCPY(HB_SKETCHBOARD,p,size);
	    }
	  }
	  break;
	}
	crc=CM_Compute_CRC16(0,start,dumplen+sizeof(UINT32)/* PRH_STAMP */);
	HB_WRITE_UINT16(HB_SKETCHBOARD,crc);
      }
      break;
    case HB_SKETCHBOARD:
      /* put inside all the possible. Ignore function parameters */
      HB_InitBuf_NoLock(HB_SKETCHBOARD);
      for(source=HB_NULL;source<HB_MAX;source++) {
	switch (source) {
	case HB_TMTC:
	case HB_TSB_T:
	case HB_TSB_B:
	case HB_LOG:
	case HB_MCMD:

	  /* consider extra data: */
	  switch(source) {
	  case HB_LOG: 
	    total_len=HB_Buffer[source].len+4;
	    break;
	  default:
	    total_len=HB_Buffer[source].len;
	    break;
	    
	  }

	  if(HB_IS_FULL_ENOUGH(source) && 
	     (HB_SPACE_LEFT(HB_SKETCHBOARD) >=
			   HB_HEADER_LEN+          /* header len */
			   total_len         +     /* records len */
			   sizeof(UINT16)          /* 2 Byte CRC 16 */
	      )
	     ) {
	    HB_WriteHeader(HB_SKETCHBOARD,
			     HB_PktType[source],
			     total_len        +     /* len */
			     sizeof(UINT16)         /* 2 byte crc 16 */
			     ,obt);
	    start=HB_END_BYTE_PTR(HB_SKETCHBOARD);
	    /* write extra data: */
	    switch(source) {
	    case HB_LOG: 
	      {
		UINT32 tstamp=LU_GetCompilationTimeStamp();
		HB_WRITE_UINT32(HB_SKETCHBOARD,tstamp);
	      }
	      break;
	    defaul:
	    }
	    HB_WRITE_MEMCPY(HB_SKETCHBOARD,HB_Buffer[source].buf,HB_Buffer[source].len);
	    crc=CM_Compute_CRC16(0,start,total_len);
	    HB_WRITE_UINT16(HB_SKETCHBOARD,crc);
	    HB_InitBuf_NoLock(source);
	  }

	  break;
	case HB_MISC:
	  if(HB_IS_FULL_ENOUGH(source) && 
	     (HB_SPACE_LEFT(HB_SKETCHBOARD) >=
	      HB_HEADER_LEN+          /* header len */
	      HB_Buffer[source].len  /* records len */
	      )
	     ) {
	    start=HB_END_BYTE_PTR(HB_SKETCHBOARD);
	    HB_WRITE_MEMCPY(HB_SKETCHBOARD,HB_Buffer[source].buf,HB_Buffer[source].len);
	    HB_InitBuf_NoLock(source);
	  }
	  break;
	default:
	  break;
	}
      }
      break;
    case HB_LOG:
      if(HB_SPACE_LEFT(HB_LOG) < len+sizeof(obt))
	s=CM_RC_NO_SPACE_LEFT;
      else {
	HB_WRITE_UINT32(HB_LOG,obt);
	HB_WRITE_MEMCPY(HB_LOG,buf,len);
	HB_RecordsCounter[HB_LOG]++;
      }
      HB_IS_ALMOST_FULL(bufid);
      break;
    case HB_TSB_T:
    case HB_TSB_B:
      if(HB_SPACE_LEFT(bufid) <
	 sizeof(UINT32) + /* obt */
	 len              /* buffer len */
	 ) {
	s=CM_RC_NO_SPACE_LEFT;
      }else{
	start=HB_END_BYTE_PTR(bufid);
	HB_WRITE_UINT32(bufid,obt);
	HB_WRITE_MEMCPY(bufid,buf,len);
	HB_RecordsCounter[bufid]++;
	HB_IS_ALMOST_FULL(bufid);
      }
      break;
    case HB_MCMD:
      if(HB_SPACE_LEFT(HB_MCMD) < 
	 sizeof(UINT32) + /* obt */
	 len +            /* mcmd len */
	 sizeof(UINT16))  /* crc 16 */
	s=CM_RC_NO_SPACE_LEFT;
      else {
	start=HB_END_BYTE_PTR(HB_MCMD);
	HB_WRITE_UINT32(HB_MCMD,obt);
	HB_WRITE_MEMCPY(HB_MCMD,buf,len);
	crc=CM_Compute_CRC16(0,start,sizeof(UINT32)+len);
	HB_WRITE_UINT16(HB_MCMD,crc);
	HB_RecordsCounter[HB_MCMD]++;
      }
      HB_IS_ALMOST_FULL(bufid);
      break;
    case HB_TMTC:
      if(HB_SPACE_LEFT(HB_TMTC) <
	 sizeof(UINT32)         +  /* OBT */
	 /* sizeof(tmtc_tmp_array) +  /* size of the TMTC array */
	 16*2+16*1+1+4          +
	 1                         /* 1 byte CRC */
	 )
	s=CM_RC_NO_SPACE_LEFT;
      else {
	start=HB_END_BYTE_PTR(HB_TMTC);
	total_len=HB_BUFLEN(HB_TMTC);

	HB_WRITE_UINT32(HB_TMTC,obt);
	TM_piGetAllTMValue(tmtc_tmp_array);

	
	//HB_WRITE_MEMCPY(HB_TMTC,tmtc_tmp_array,sizeof(tmtc_tmp_array));
	

#define TMTC_PACK_BIT(target,tm_id) target = (target<<1)|(tmtc_tmp_array[tm_id] ? 1 : 0)

	tm_val=0;

	/* DIAG ACQ and BI LEVEL DIAG ACQ */
	/* MSB */
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM1);
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM2);
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM3);
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM4);
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM5);
	TMTC_PACK_BIT(tm_val,TM_KRB_IPM6);

	TMTC_PACK_BIT(tm_val,TM_KHB_HOT_LATCHUP);
	TMTC_PACK_BIT(tm_val,TM_KHB_COLD_LATCHUP);

	TMTC_PACK_BIT(tm_val,TM_IDAQ_HOT_ALARM);
	TMTC_PACK_BIT(tm_val,TM_IDAQ_COLD_ALARM);

	TMTC_PACK_BIT(tm_val,TM_VCB_STANDBY);

	TMTC_PACK_BIT(tm_val,TM_VRL_HOT);
	TMTC_PACK_BIT(tm_val,TM_VRL_COLD);

	TMTC_PACK_BIT(tm_val,TM_PSB_ALARM);

	TMTC_PACK_BIT(tm_val,TM_TOFHV_HOT_ALARM);
	TMTC_PACK_BIT(tm_val,TM_TOFHV_COLD_ALARM);

	HB_WRITE_UINT16(HB_TMTC,tm_val);

	/* TH ANA */
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_IPM_TH]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_S1_TH]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_S4_TH]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_S4_ND_PLATE_TH]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_TRK_TH1]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_TRK_TH2]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_FLUID_IN_TH]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_FLUID_OUT_TH]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_VME_TH]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_DCDC_TH]);
	
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_CPU_TH1]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_CPU_TH2]);

	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_IPM_CPU_TH]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_VRL_TH1]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_VRL_TH2]);
	HB_WRITE_UINT16(HB_TMTC,tmtc_tmp_array[TM_VME_COOL_TH]);
	
	/* DEA ANA */
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM1]);
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM2]);
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM3]);
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM4]);
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM5]);
	HB_WRITE_UINT8(HB_TMTC,tmtc_tmp_array[TM_IPM_MOV_IPM6]);
	
	
	crc=CM_Compute_CRC16(0,start,HB_BUFLEN(HB_TMTC)-total_len);
	b=crc & 0xff;
	HB_WRITE_UINT8(HB_TMTC,b);
	HB_RecordsCounter[HB_TMTC]++;
      }
      HB_IS_ALMOST_FULL(bufid);
      break;
    case HB_MISC:
      // HB_InitBuf_NoLock(bufid);
      if(HB_SPACE_LEFT(HB_MISC) >=
	 HB_HEADER_LEN+        /* header len */
	 len+                 /* records len */
	 sizeof(UINT16)       /* 2 byte crc 16 */
	 ){
	HB_WriteHeader(bufid,
		       miscpkttype,
		       len+2,
		       obt);
	start=HB_END_BYTE_PTR(bufid);
	memcpy(start,dataptr,len);
	HB_Buffer[bufid].len+=len;
	crc=CM_Compute_CRC16(0,start,len);
	HB_WRITE_UINT16(HB_MISC,crc);
      }
      else
	s=CM_RC_NO_SPACE_LEFT;
      HB_IS_ALMOST_FULL(bufid);     
      break;
    case HB_USERDATA0:
    case HB_USERDATA1:
    case HB_USERDATA2:
    case HB_USERDATA3:
      /* append bytes in the buffer: */
      if(HB_SPACE_LEFT(bufid) < len)
	s=CM_RC_NO_SPACE_LEFT;
      else {
	start=HB_END_BYTE_PTR(bufid);
	memcpy(start,buf,len);
	HB_Buffer[bufid].len+=len;
      }
      break;
    default:
      s=CM_RC_INTERNAL_ERR;
      break;
    }
  }else
    s=CM_RC_RES_ERR;
  if(HB_SemV())
    s=CM_RC_RES_ERR;
  /* TBD: Log this? 
  if(s == CM_RC_NO_SPACE_LEFT && bufid != HB_LOG)
  LU_INFN_LOG(LU_CRITICAL, LU_MASK(__FILEID__),__FILEID__,__LINE__,s);
  */
  return s;
}


status_code HB_Userdata2ArrTab(BYTE what,HB_BUF bufid,BYTE id,UINT16 crc) {
  status_code s;
  UINT32 size;
  if(bufid < HB_USERDATA_FIRST || bufid > HB_USERDATA_LAST)
    return CM_RC_INVALID_BUFFER_ID;
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    switch(what) {
    case HB_2ARR:
      s=PRH_SIZEOF_ARR(id,&size);
      break;
    case HB_2TAB:
      s=PRH_SIZEOF_TABLE(id,&size);
      break;
    }
    if(s==CM_RC_SUCCESSFUL) {
      if(size == HB_Buffer[bufid].len) {
	DAQ_Compute_CRC16(&HB_Buffer[bufid]);
	if(HB_Buffer[bufid].crc16 == crc) {
	  switch(what) {
	  case HB_2TAB:
	    s=PRH_int_set_tab_raw(id,HB_Buffer[bufid].buf);
	    break;
	  case HB_2ARR:
	    s=PRH_int_set_arr_raw(id,HB_Buffer[bufid].buf);
	    break;
	  }
	}
	else
	  s=CM_RC_CRC_MISMATCH;
      }
      else 
	s=CM_RC_INVALID_BUFFER_SIZE;
    }
    HB_SemV();
    return s;
  }else
    return CM_RC_RES_ERR;
}

status_code HB_Userdata2Arr(HB_BUF bufid,BYTE id,UINT16 crc) {
  return HB_Userdata2ArrTab(HB_2ARR,bufid,id,crc);
}

status_code HB_Userdata2Tab(HB_BUF bufid,BYTE id,UINT16 crc) {
  return HB_Userdata2ArrTab(HB_2TAB,bufid,id,crc);
}

status_code HB_Userdata2Buf(HB_BUF bufid,DAQ_CMD_BUF *target,UINT16 crc) {
  status_code s;
  UINT32 size;
  if(bufid < HB_USERDATA_FIRST || bufid > HB_USERDATA_LAST)
    return CM_RC_INVALID_BUFFER_ID;
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    DAQ_Compute_CRC16(&HB_Buffer[bufid]);
    if(HB_Buffer[bufid].crc16 != crc){
      /*@LOG error in CRC loading external buffer - crc */
      LU_INFN_LOG(LU_CRITICAL|LU_HA, LU_MASK(__FILEID__),__FILEID__,__LINE__,crc);
      s=CM_RC_CRC_MISMATCH;
    }
    else 
      s=DAQ_Format_CopyBuffer(target,&HB_Buffer[bufid]);
    HB_SemV();
    return s;
  }else
    return CM_RC_RES_ERR;
}


status_code HB_WriteToPIF(HB_BUF buf_id) {
  status_code s;
  SM_STRSTAT status;
  unsigned int count=0;
  BOOL exit = FALSE;
  rtems_event_set out;
  // FT_piChangeAcqMode(SM_DIRECT); commented out because cannot change acq mode while a run is in progress
  if(HB_SemP() == CM_RC_SUCCESSFUL) {
    /* close the buffer : - end of buffer */

    // PADDING 64 
    while(HB_Buffer[buf_id].len%64)
      HB_WRITE_UINT8(buf_id,0xCA/*00*/);
    
    while(count < PRH_VAR_HB_N_ATTEMPT_WRITE2PIF && !exit) {
      count++;
      status = DAQ_SaveBuffer2MM(&HB_Buffer[buf_id],FS_HK,PRH_VAR_HB_WRITE2PIF_TIMEOUT);
      if(status != CM_RC_SUCCESSFUL) {
	s = status;
	OS_piTaskSuspend(PRH_VAR_HB_WAIT_ON_FAILED_ATTEMPT_WRITE2PIF);
      }else {
	HB_InitBuf_NoLock(buf_id);
	exit = TRUE;
	s = CM_RC_SUCCESSFUL;
      }
    }
    if(!exit) {
      /* loose data */
      /* TBD: what to do here? */
      HB_InitBuf_NoLock(buf_id);
    }
    
  }else
    s=CM_RC_RES_ERR;
  if(HB_SemV())
    s=CM_RC_RES_ERR;
  
  /*if(s==CM_RC_SUCCESSFUL)
    HB_Store(buf_id,0,NULL,0);
  */
  if(s || !exit)
    /*@LOG log the loose of data - status */
    LU_INFN_LOG(LU_CRITICAL|LU_HA, LU_MASK(__FILEID__),__FILEID__,__LINE__,s);
  return s;
}


