/****************************************************************************
 *  F i l e   D a t a                                                        
 *  $Id: KHB_Driver_INFN.c,v 1.1.1.1 2006/04/25 09:00:20 kusanagi Exp $
 *  $Revision: 1.1.1.1 $
 *  $Date: 2006/04/25 09:00:20 $
 *  $RCSfile: KHB_Driver_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: kusanagi $
 *               :                                                           
 ****************************************************************************
 *  U p d a t i n g                                                          

 *  $Log: KHB_Driver_INFN.c,v $
 *  Revision 1.1.1.1  2006/04/25 09:00:20  kusanagi
 *  These program extract in an XML format the info contained into the ROOT files generated by YODA from the PAMELA data. To visualize the XML files in a more human readable format a collection of XSL files are given in the Data subfolder.
 *
 *  Revision 1.73  2005/03/20 18:20:32  sebastiani
 *  PRH_VAR_RM_IDAQONLYACQ cancelled
 *
 *  Revision 1.72  2005/02/24 16:51:19  sebastiani
 *  more comments in logs
 *
 *  Revision 1.71  2005/02/21 08:58:29  sebastiani
 *  all log comments completed
 *
 *  Revision 1.70  2005/02/19 10:19:38  sebastiani
 *  ALM_S4_CALIB_00_HARD,ALM_S4_CALIB_00_SOFT,ALM_S4_128TRIGGER_0 added
 *
 *  Revision 1.69  2005/01/26 18:46:48  sebastiani
 *  new bug fixes for WS
 *
 *  Revision 1.68  2005/01/07 15:41:51  sebastiani
 *  fix alarm precedure
 *  add exp 64 delay patch
 *  removed unused sleep
 *
 *  Revision 1.67  2004/12/17 12:46:40  faber
 *  ALARM REGISTER aligned to be 32 bit. memory aling core dump (should be) fixed
 *
 *  Revision 1.66  2004/12/15 09:21:33  sebastiani
 *  KHB_ALARM_MASK_ALL introduced
 *
 *  Revision 1.65  2004/11/19 15:14:52  sebastiani
 *  PRH_EXTERN_{VAR,ARR,TABLE} removed and put them on the autogenerated parameter heeader file
 *
 *  Revision 1.64  2004/11/18 16:02:34  sebastiani
 *  GAS/TRD removed
 *
 *  Revision 1.63  2004/11/05 09:36:35  sebastiani
 *  first version of the PM state machine. tried but not deeply tested
 *
 *  Revision 1.62  2004/10/19 16:59:27  sebastiani
 *  first text for IPM/ciclyc
 *
 *  Revision 1.61  2004/10/08 15:57:51  sebastiani
 *  fix power hot cold variables settings.
 *  fix ws
 *  added function to set khb hot or cold
 *
 *  Revision 1.60  2004/10/04 08:25:06  sebastiani
 *  *** empty log message ***
 *
 *  Revision 1.59  2004/09/17 15:01:00  faber
 *  LU_INFN_LOG flags fixing
 *
 *  Revision 1.58  2004/09/14 13:05:37  alfarano
 *  update TM constants and definitions
 *
 *  Revision 1.57  2004/08/27 13:30:39  alfarano
 *  cvs header
 *
 *  Revision 1.1  2003/10/03 16:12:26  faber
 *  *** empty log message ***
 *
 *                                                                           
 *****************************************************************************/
/*============================= Include File ================================*/

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

#include <src/TM_TCManager/TMTCManager/TM_TMTCManager_p.h>
#include <src/INFN/CM_Common_INFN.h>
#include <src/INFN/KHB_Driver_INFN.h>


/*============================== global variables  ==========================*/

/* this variable contains which serial line is enabled: 
   SERIAL_LINE_1 or SERIAL_LINE_2 
*/ 
static BYTE KHB_SerialLine;

/* this variable contains which DBL line is enabled */ 
static UINT32 KHB_DBC_Status;

/* Code for serial write and read operation from KHB and DBC lines */

static KHB_ADDR_TYPE KHB_SerialAddress[2]={{TM_KHB_HOT,TM_KHB_DS_HOT,KHB_DBC0_HI_1,KHB_DBC1_HI_1},
					   {TM_KHB_COLD,TM_KHB_DS_COLD,KHB_DBC0_HI_2,KHB_DBC1_HI_2}};

/*============================ Functions ====================================*/

status_code KHB_Init() 
{
  KHB_SetSerialLine(CM_HOT);
  KHB_DBC_Status = 0; 
  
  return SUCCESSFUL;
}

status_code KHB_InitBoard(/*XX*/) 
{
  status_code status;
  UINT16 reg;

  //KHB_SetSerialLine(XX);

  status = KHB_HWReset();

  // some delay here ? 
  
  if (status== CM_RC_SUCCESSFUL)
    {
      status = KHB_UpdateMaskRegister(KHB_ALARM_MASK_NONE,KHB_PRESET);
      if(status == CM_RC_SUCCESSFUL) {
	status=KHB_ReadStatusRegister(&reg);
	if(status != CM_RC_SUCCESSFUL || ((reg & KHB_STATUS_MASK) != KHB_STATUS_VALUE) ) {
	  /*@LOG InitBoard: status register not the same as written - khb_status_reg */
	  LU_INFN_LOG(LU_WARNING|LU_HA,LU_MASK(__FILEID__),__FILEID__,__LINE__,reg);
	  status= CM_RC_KHB_ERROR;
	}
      }
    }
  
#if 0
  /* old code: no special reason to work on mask register */
  if (!status) 
    {
      status = KHB_UpdateMaskRegister(KHB_START_MASK,KHB_PRESET);
      
      if (!status)
	{
	  status = KHB_ReadMaskRegister(&reg);
	  
	  if(!status)
	    if (reg != KHB_START_MASK)
	      status = CM_RC_INTERNAL_ERR;
	}
    }
  
  if (!status)
    status = KHB_UpdateMaskRegister(KHB_MASK_NONE,KHB_PRESET);
#endif 
  /*@LOG InitBoard trace - status */
  LU_INFN_LOG(LU_DEBUG_TRACE,LU_MASK(__FILEID__),__FILEID__,__LINE__,status);  
  return(status);
}

/*****************************************************************************/
/*  
 *  KHB_SetSerialLine
 *
 *  Selects the serial line to use 
 *
 *  Input parameters: 
 *                   line = selects SERIAL_LINE_1 or SERIAL_LINE_2 
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_SetSerialLine(CM_HOT_COLD hl)
{
  if(hl == CM_HOT)
    KHB_SerialLine = KHB_SERIAL_HOT;
  else
    KHB_SerialLine = KHB_SERIAL_COLD;
  return(SUCCESSFUL);
}

/*****************************************************************************/
/*  
 *  KHB_GetSerialLine
 *
 *  Selects the serial line to use 
 *
 *  Input parameters: 
 *                   pointer to khb hot cold status (selected by SERIAL_LINE_1 or SERIAL_LINE_2) 
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_GetSerialLine(CM_HOT_COLD *hl)
{
  if(hl){
    if(KHB_SerialLine == KHB_SERIAL_HOT)
      *hl = CM_HOT;
    else
      *hl = CM_COLD;
  }
  return(SUCCESSFUL);
}


/*****************************************************************************/
/*  
 *  KHB_SendFECommand
 *
 *  Sends a write command to KHB 
 *
 *  Input parameters: 
 *                    link = selects which link to send the commnand
 *                    counter = sets how many words will follow the command
 *                    expected = sets how many words are expected from reply
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_SendFECommand(BYTE link,BYTE counter,BYTE expected,UINT16 *buffer)
{
  int i;
  status_code status;
  KHB_COMMAND_TYPE KHB_Command;
  TM_TC_ML com_to_send[4];
  
  KHB_Command.link = link;
  KHB_Command.clear = 0;
  KHB_Command.output = NULL;
  KHB_Command.counter_command = counter+1;                  // including end pattern
  KHB_Command.counter_answer = expected;                 

  com_to_send[0].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  com_to_send[0].Value = (UINT32)*(UINT16*)&KHB_Command;
  
  for (i=1; i < counter+1; i++)
    {
      com_to_send[i].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
      com_to_send[i].Value = (UINT32)*buffer++;
    }
  
  com_to_send[i].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  com_to_send[i].Value = KHB_END_PATTERN;
  
  // status = TM_piSendTC(KHB_SerialAddress[KHB_SerialLine].writeAddr,*(UINT16*)&KHB_Command);
  //  if (!status)
  status = TM_piSendMLTC(com_to_send,counter+2);
  
  return(status);
}


/*****************************************************************************/
/*  
 *  KHB_WriteMaskRegister
 *
 *  Sends a write command to KHB 
 *
 *  Input parameters: maskvalue  = set the mask value to write
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_WriteMaskRegister(UINT16 mask_reg)
{
  int i;
  status_code status;
  KHB_COMMAND_TYPE KHB_Command;
  TM_TC_ML com_to_send[3];

  KHB_Command.link = KHB_INTERNAL_LINK;
  KHB_Command.clear = 0;
  KHB_Command.counter_command = 2;
  KHB_Command.counter_answer = NULL;
  KHB_Command.output = NULL;
  
  for(i=0; i < 3; i++)
    com_to_send[i].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  
  com_to_send[0].Value = *(UINT16*)&KHB_Command;
  com_to_send[1].Value = mask_reg;
  com_to_send[2].Value = KHB_END_PATTERN;

  status = TM_piSendMLTC(com_to_send,3);
  return(status);
}


/*****************************************************************************/
/*  
 *  KHB_RequestKHBReg
 *
 *  Sends a write command to KHB 
 *
 *  Input parameters: 
 *                    output = sets which register to read
 *                    expected = sets how many words are expected from reply in case 
 *                               object is data buffer  
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_RequestKHBReg(BYTE output,BYTE expected)
{
  status_code status;
  KHB_COMMAND_TYPE KHB_Command;
  TM_TC_ML com_to_send[2];

  KHB_Command.link = NULL;
  KHB_Command.clear = 0;
  KHB_Command.output = output;
  KHB_Command.counter_command = 1;
  KHB_Command.counter_answer = expected;

  com_to_send[0].Code = com_to_send[1].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  com_to_send[0].Value = *(UINT16*)&KHB_Command; 
  com_to_send[1].Value = KHB_END_PATTERN;
  
  status = TM_piSendMLTC(com_to_send,2);
  return(status);
}


/*****************************************************************************/
/*  
 *  KHB_ReadMaskRegister
 *
 *  read mask register  
 *
 *  Input parameters: none
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_ReadMaskRegister(UINT16 *value)
{
  status_code status;
  UINT16 temp;
  static int sleep0=2,sleep1=1;

  if(sleep0)
    OS_piTaskSuspend (sleep0);

  status = KHB_RequestKHBReg(MASK_REG,0);

  if (!status)
    {
      status = KHB_SetKHBMode(READ_OBJ_MODE);
      
      if(sleep1)
	OS_piTaskSuspend (sleep1);
      
      if (!status)
	{
	  status = TM_piGetKHBValue(KHB_SerialAddress[KHB_SerialLine].readAddr,&temp,1); 
	  if (!status)
	    {
	      *value = temp;
	      status = KHB_SetKHBMode(READ_STATUS_MODE);
	    }
	}
    }
  return(status);
}

/*****************************************************************************/
/*  
 *  KHB_UpdateMaskRegister
 *
 *  update mask register  
 *
 *  Input parameters: none
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_UpdateMaskRegister(UINT16 bitmask,BYTE action)
{
  UINT16 KHB_MaskRegister;
  status_code status;
  
  status = KHB_ReadMaskRegister(&KHB_MaskRegister);
  
  switch (action)
    {
    case KHB_BITSET :
      KHB_MaskRegister |= bitmask;
      break;
    case KHB_BITRESET : 
      KHB_MaskRegister &= ~bitmask;
      break;
    case KHB_PRESET :
      KHB_MaskRegister = bitmask;
      break;
    }
  
  if (!status)
    status = KHB_WriteMaskRegister(KHB_MaskRegister);
  
  return(status);
}


/*****************************************************************************/
/*  
 *  KHB_ReadStatusRegister 
 *
 *  Read the status register (provided that DBC1 is high) 
 *
 *  Input parameters: status_reg will contain the status register read
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_ReadStatusRegister(UINT16 *status_reg) 
{
  status_code status;

  status = KHB_SetKHBMode(READ_STATUS_MODE);

  if (!status) {
    status = KHB_ReadCurrentVal(status_reg);
    *status_reg ^= KHB_STS_XORED_BITS;
    /* apply low level mask to disable definitively dummy alarms: */    
    *status_reg &= ~((UINT16)PRH_VAR_KHB_STATUS_REG_LOW_LEVEL_MASK);
  }
  
  return(status);
}

/*****************************************************************************/
/*  
 *  KHB_ReadAlarmRegister
 *
 *  Read the alarm register  
 *
 *  Input parameters : alarm32 will contain two words (16 bit) from the alarm 
 *                     registers:
 *                     the higher 16 bit will contain all errors occured   
 *                     the lower 16 bit will contain the first error occured 
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_ReadAlarmRegister(UINT32 *alarm)
{
  status_code status,modestatus=CM_RC_SUCCESSFUL;
  UINT16 tmp;
  
  static int sleep2=1;
  
  status = KHB_SetKHBMode(READ_OBJ_MODE);
  
  if (!status)
    {
      status = KHB_RequestKHBReg(ALARM_REG,0);

      if (!status)
	{
	  status = KHB_ReadCurrentVal(&tmp);
	  if (!status)
	    {
	      *alarm = (( (tmp & KHB_ALARM_MASK_ALL ) ^ KHB_ALARM_XORED_BITS)<<16);
	      if(sleep2)
		OS_piTaskSuspend (sleep2);
	      status = KHB_ReadCurrentVal(&tmp);
	      if (!status)
		{
		  *alarm |= (tmp & KHB_ALARM_MASK_ALL) ^ KHB_ALARM_XORED_BITS;
		  /* apply low level mask to disable definitively dummy alarms: */
		  *alarm &= ~((UINT16)PRH_VAR_KHB_ALARM_REG_LOW_LEVEL_MASK);
		}
	    }	  
	}
      modestatus = KHB_SetKHBMode(READ_STATUS_MODE);   
    }
  return ((status!=CM_RC_SUCCESSFUL) ? status : modestatus);
}

/*****************************************************************************/
/*  
 *  KHB_ReadBuffer
 *
 *  Request for buffer   
 *
 *  Input parameters: expected = word expected to receive 
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_ReadBuffer(BYTE expected,UINT16 *buffer) 
{
  status_code status;
  UINT16 status_reg;
  
  status = KHB_SetKHBMode(READ_OBJ_MODE);
  
  if (!status)
    status = KHB_RequestKHBReg(BUFFER,0); 
  
  if (!status)
    status = TM_piGetKHBValue(KHB_SerialAddress[KHB_SerialLine].readAddr,buffer,expected);
  
  status = KHB_SetKHBMode(READ_STATUS_MODE);

  return(status);
}

/*****************************************************************************/
/*  
 *  KHB_Clear
 *
 *  Clear the KHB buffer  
 *
 *  Input parameters: none 
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_SendClearFE()
{
  status_code status;
  KHB_COMMAND_TYPE KHB_Command;
  TM_TC_ML com_to_send[2];
  
  KHB_Command.link = NULL;
  KHB_Command.clear = 1;
  KHB_Command.output = NULL;
  KHB_Command.counter_command = 1;
  KHB_Command.counter_answer = NULL;

  com_to_send[0].Code = com_to_send[1].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  com_to_send[0].Value = *(UINT16*)&KHB_Command; 
  com_to_send[1].Value = KHB_END_PATTERN;
  
  status = TM_piSendMLTC(com_to_send,2);
  return(status);
}

status_code KHB_ReadCurrentVal(UINT16 *value)
{
  status_code status;
  UINT16 tmp;

  status = TM_piGetKHBValue(KHB_SerialAddress[KHB_SerialLine].readAddr,&tmp,1);
  *value = tmp;
  return(status);
}

status_code KHB_SendTrigger()
{
  status_code status;
  KHB_COMMAND_TYPE KHB_Command;
  TM_TC_ML com_to_send[2];

  KHB_Command.link = NULL;
  KHB_Command.clear = 1;
  KHB_Command.output = NULL;
  KHB_Command.counter_command = 1;
  KHB_Command.counter_answer = NULL;
  KHB_Command.trigger = 0xa;
  
  com_to_send[0].Code = com_to_send[1].Code = KHB_SerialAddress[KHB_SerialLine].writeAddr;
  com_to_send[0].Value = *(UINT16*)&KHB_Command; 
  com_to_send[1].Value = KHB_END_PATTERN;

  status = TM_piSendMLTC(com_to_send,2);
  return(status);
}

/*****************************************************************************/
/*  
 *  KHB_HWReset
 *
 *  Reset the KHB  
 *
 *  Input parameters: none 
 *                    
 * 
 *  Output parameters: status_code
 *
 */
/*****************************************************************************/

status_code KHB_HWReset()
{
  status_code status;

  //  static int sleep0=1;
  //  if(sleep0)
  //    OS_piTaskSuspend (sleep0);

  
  KHB_SetDBC0(KHB_BITRESET);
  
  status =  TM_piSendTC(TM_DBL_CMD,KHB_DBC_Status);

  if (!status)
    {
      KHB_SetDBC0(KHB_BITSET);
      KHB_SetDBC1(KHB_BITSET);
      //      if(sleep0)
      // OS_piTaskSuspend (sleep0);
      status =  TM_piSendTC(TM_DBL_CMD,KHB_DBC_Status);
    }
  return(status);
}

status_code KHB_SetKHBMode(KHB_MODE mode)
{
  status_code status;
  
  if (mode == READ_STATUS_MODE)
    KHB_SetDBC1(KHB_BITSET);
  else
    KHB_SetDBC1(KHB_BITRESET);
  
  status =  TM_piSendTC(TM_DBL_CMD,KHB_DBC_Status);

  return(status);
}

status_code KHB_SetDBC0(BYTE status)
{
  if (status == KHB_BITSET)
    KHB_DBC_Status |= KHB_SerialAddress[KHB_SerialLine].dbc0hi;
  else
    KHB_DBC_Status &= ~KHB_SerialAddress[KHB_SerialLine].dbc0hi;

  return CM_RC_SUCCESSFUL;
}

status_code KHB_SetDBC1(BYTE status)
{
  if (status == KHB_BITSET)
    KHB_DBC_Status |= KHB_SerialAddress[KHB_SerialLine].dbc1hi;
  else
    KHB_DBC_Status &= ~KHB_SerialAddress[KHB_SerialLine].dbc1hi;

  return CM_RC_SUCCESSFUL;
}



// Test Functions


status_code KHB_Log()
{
  status_code statusMask,statusStatus;
  UINT16 mask;
  UINT16 reg;
  
  statusMask = KHB_ReadMaskRegister(&mask);
  statusStatus = KHB_ReadStatusRegister(&reg);
  /*@LOG KHB Log: mask */
  LU_INFN_LOG(LU_NORMAL_TRACE,LU_MASK(__FILEID__),__FILEID__,__LINE__,mask);  
  /*@LOG KHB Log: reg */
  LU_INFN_LOG(LU_NORMAL_TRACE,LU_MASK(__FILEID__),__FILEID__,__LINE__,reg);
  /*@LOG KHB Log: status_mask */
  LU_INFN_LOG(LU_NORMAL_TRACE,LU_MASK(__FILEID__),__FILEID__,__LINE__,statusMask);
  /*@LOG KHB Log: status_khb_status */
  LU_INFN_LOG(LU_NORMAL_TRACE,LU_MASK(__FILEID__),__FILEID__,__LINE__,statusStatus);

  return(CM_RC_SUCCESSFUL);
}

status_code KHB_TestBoard(unsigned short selected_test)
{
  int x;
  static int n;
  int test;
  int a=1,b=1,c=1,d=1,e=1;
  UINT16 value[3];
  
  n = 1000; 
  test = selected_test;

  switch(test)
    {
    case 0:
      {
	int i;
	UINT16 mask;
	status_code status;

	status = KHB_UpdateMaskRegister(KHB_START_MASK,KHB_PRESET);
	
	for (i=0; i < 1000; i++)
	  {
	    status = KHB_ReadMaskRegister(&mask);
	    if(!status)
	    if (mask != KHB_START_MASK)
	      {
		status = CM_RC_INTERNAL_ERR;
		break;
	      }
	  }
      }
      break;
    case 1:
       {
	int i;
	UINT16 reg;
	status_code status;

	for (i=0; i < 1000; i++)
	  {
	    status = KHB_ReadStatusRegister(&reg);
	    if (reg != KHB_STATUS_VALUE)
	      {
		status = CM_RC_INTERNAL_ERR;
		break;
	      }
	  }
       }
       break;
    case 2:
      {
	UINT32 alarm;
	UINT16 statusw; 
	int a=1,b=1;
	status_code status;
	
	if (a) 
	  status = KHB_ReadAlarmRegister(&alarm);
	if (b)
	  status = KHB_ReadStatusRegister(&statusw);
      }
      break;
      
    }
}


UINT32 KHB_GetSerialLineReadAddress(){
  return KHB_SerialAddress[KHB_SerialLine].readAddr;
}
