/****************************************************************************
/*  F i l e   D a t a                                                        
/*                                                                           
/*  Module       : BasicSW                                                   
/*  C.I. No.     :                                                           
/*  $Revision: 1.1.1.1 $
/*  $Date: 2006/04/25 09:00:20 $
/*  Belonging to :                                                           
/*               :                                                           
/*  $RCSfile: PD_PatchDumpManager_int.c,v $
/*  Program Type :                                                           
/*  Sub-modules  :                                                           
/*                                                                           
/****************************************************************************
/*  S W   D e v e l o p m e n t   E n v i r o n m e n t                      
/*                                                                           
/*  Host system  :                                                           
/*  SW Compiler  :                                                           
/*  $Author: kusanagi $
/*               :                                                           
/****************************************************************************
/*  U p d a t i n g                                                          
/*                                                                           
/*  $Log: PD_PatchDumpManager_int.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.9  2005/03/20 18:16:53  sebastiani
/*  avoided compilation warning
/*
/*  Revision 1.8  2005/03/06 14:53:22  sebastiani
/*  fix check different value
/*
/*  Revision 1.7  2005/02/21 08:58:28  sebastiani
/*  all log comments completed
/*
/*  Revision 1.6  2005/02/19 10:16:17  sebastiani
/*  efficient write in EEPROM
/*
/*  Revision 1.5  2004/09/28 15:36:17  sebastiani
/*  interrupt manager fix
/*
/*  Revision 1.4  2004/09/17 15:01:00  faber
/*  LU_INFN_LOG flags fixing
/*
/*  Revision 1.3  2003/11/18 09:01:14  alfarano
/*  laben patch fixes some problems
/*
/*  Revision 1.2  2003/10/21 16:09:12  alfarano
/*  LU_LOG_INFN replacement for all remaining original log functions
/*
/*  Revision 1.1.1.1  2003/08/04 09:40:21  sebastiani
/*  Imported sources laben rel. 19.06.2003 integrated with pam2
/*
/*  Revision 1.10  2002/09/11 15:33:39  zulia
/*  correct checkParameterValue
/*  (memory address was casted to UWORD)
/*
/*  Revision 1.9  2002/08/06 12:08:27  zulia
/*  the Patch mcmd is refused if the number of data words not are multiply of 32 bits
/*
/*  Revision 1.8  2002/08/05 14:25:35  zulia
/*  Fixed Patch & Dump
/*
/*  Revision 1.7  2002/05/09 08:16:34  zulia
/*  *  acceptance release
/*
/*                                                                           
/*****************************************************************************/

 
/*============================= Include File ================================*/
  
#include <src/BasicSW/PatchDumpManager/PD_PatchDumpManager_int.h>
#include <src/HKManager/HistoryArea/HA_HistoryArea_p.h>
#include <src/BasicSW/CrimeaDriver/CD_CrimeaDriver_p.h>

#include <src/INFN/LU_SourceFileID_INFN.h>
#define __FILEID__ _PD_PatchDumpManager_int__c
#include <src/INFN/PRH_ParamHandler_INFN_auto.h>
#include <src/INFN/PRH_ParamHandler_INFN.h>
#include <src/INFN/LU_LogUtility_INFN.h>

LU_DECL_MASK();

/*****************************************************************************/
/*=============================  Object constant ============================*/


/*****************************************************************************/
/*============================= Object variables ============================*/

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

/* P a t c h D u m p M a n a g e r  O P E R A T I O N A L  F U N C T I O N S */


/*****************************************************************************/
/* @Function: PD_ifPatch                                                     */
/* @Purpose :                                                                */
/*  This function executes the Patch macrocommand performing the following   */
/*  actions:                                                                 */
/*  _ checks the number of words to be patched                               */
/*  _ checks the supervisor memory selection                                 */
/*  _ checks if address is in the allowed range                              */
/*  _ writes the patch at the correct address                                */
/*                                                                           */
/* @@                                                                        */
/* @Parameter Name      @Mode   @Description                                 */
/*  PtrMcmd              IN     pointer to the macrocommand header structure */
/*  PatchBuff            IN     pointer to the patch RAM area                */
/* @@                                                                        */
/*****************************************************************************/
void PD_ifPatch(MA_HEADER_MCMD* PtrMcmd, UWORD* PatchBuff)
{
  UINT* memAddrToPatch;
  UWORD  nWord16ToLoad;
  UWORD  smsPatch;
  UWORD  error;
  UWORD* pw;
  UINT   timetagFlag; 
  MsgTsk sndMsg;

    pw = (UWORD*)(PtrMcmd->PtrMCMD);

    /* retrieves the number of words to be patched from the 
       macrocommand length (expressed in multiples of 16bit words) */  
    nWord16ToLoad  = pw[2] & 0x0FFF;
    
    /* subtracts 8 words from Mcmd length (mcmd header+end identifier) */
    if ( nWord16ToLoad > 8 ) 
    {
        nWord16ToLoad -= 8;
    }
    
    /* determinates if it is a RAM or EEPROM patch */
    if( pw[5] & PD_PATCH_SMS_MASK )
    {
    	if ( pw[5] & PD_EEPROM_BANK_SELECT )
    	{
            memAddrToPatch = (UINT*)(PD_EEPROM_BANK1_ADDR_START + (((pw[5]&0x00FF)<<16) | pw[6]));
            smsPatch = PD_EEPROM_BANK1_PATCH;
        }
        else
        {
            memAddrToPatch = (UINT*)(PD_EEPROM_BANK0_ADDR_START + (((pw[5]&0x00FF)<<16) | pw[6]));
            smsPatch = PD_EEPROM_BANK0_PATCH;
        }
    }
    else
    {
         smsPatch = PD_RAM_PATCH;
         memAddrToPatch = (UINT*)(PD_RAM_ADDR_START + (((pw[5]&0x00FF)<<16) | pw[6]));
    }
    error = PD_ifCheckParamValues(memAddrToPatch, nWord16ToLoad>>1, smsPatch );

    if ( nWord16ToLoad % 2)
    {
        /* The number of word must be 32-bit multiply */
        error = HA_E2_INVALID_LENGTH;
    }
    
    if ( error == PD_PARAM_VALUES_NO_ERROR )
    {
        /* copies into private buffer the data to be patched */
        memcpy(PatchBuff, &pw[7], nWord16ToLoad<<1);
    }

    /* The function has been called by a MCMD, delete it from the partition */
    timetagFlag = *(((unsigned short* )PtrMcmd->PtrMCMD)+1) & TIMETAG_MASK ? TIMETAG_MCMD : IMMEDIATE_MCMD;
    MA_piDelBufferMCMD(PtrMcmd->PtrMCMD, timetagFlag);
    
    if ( error == PD_PARAM_VALUES_NO_ERROR )
    {
        /* writes the patch */
        if( smsPatch == PD_RAM_PATCH )
        {
            memcpy(memAddrToPatch, PatchBuff, nWord16ToLoad<<1);
        }
        else
        {
            PD_ifEEPROMWrite(memAddrToPatch, PatchBuff, nWord16ToLoad>>1);
        }
    }
    /* log in History Area*/
    // LOG_INFN HA_piLogHistoryEntry2(PtrMcmd->Type,error);
    /*@LOG Patch MCMD - error code */
    LU_INFN_LOG(LU_NORMAL_TRACE | LU_HA,LU_MASK(__FILEID__),__FILEID__,__LINE__,error);
}


/*****************************************************************************/
/* @Function: PD_ifDump                                                      */
/* @Purpose :                                                                */
/*  This function executes the Dump macrocommand performing the following    */
/*  actions:                                                                 */
/*  _ checks the number of words to be patched                               */
/*  _ checks the supervisor memory selection                                 */
/*  _ checks if address is in the allowed range                              */
/*  _ checks the append_next flag                                            */
/*  _ copies data into the dump buffer                                       */
/*                                                                           */
/* @@                                                                        */
/* @Parameter Name      @Mode   @Description                                 */
/*  PtrMcmd              IN     pointer to the macrocommand header structure */
/*  DumpBuff             IN     pointer to the dump RAM area                 */
/* @@                                                                        */
/*****************************************************************************/
void PD_ifDump(MA_HEADER_MCMD* PtrMcmd, UWORD* DumpBuff,PD_INFO* DumpInfo)
{
  UINT* memAddrToDump;
  UWORD  nWordsToDump;
  UWORD  Append_Next;
  UWORD  smsDump;
  UWORD  eepromBankSel;
  UWORD  error;
  UWORD* pw;
  UINT   timetagFlag; 
  MsgTsk sndMsg;

    /* The function has been called by a MCMD, delete it from the partition */
    pw = (UWORD*)PtrMcmd->PtrMCMD;
    /* The parameter unit is 32 bit word, and is converted in byte unit     */
    nWordsToDump  = (pw[5] & 0xFF00)>>6;
    Append_Next   =  pw[5] & 0x0001;
    smsDump       =  pw[5] & 0x0006;
    eepromBankSel =  pw[5] & 0x0004;
    
    /* determinates if it is a RAM or EEPROM dump and computes the appropriate address */
    if( smsDump == PD_RAM_DUMP )
         memAddrToDump = (UINT*)( PD_RAM_ADDR_START + (((pw[6]&0x00FF)<<16) | pw[7]) );
    else
    {
        if (eepromBankSel == PD_EEPROM_BANK0_DUMP )
            memAddrToDump = (UINT*)( PD_EEPROM_BANK0_ADDR_START + (((pw[6]&0x00FF)<<16) | pw[7]) );
        else
            memAddrToDump = (UINT*)( PD_EEPROM_BANK1_ADDR_START + (((pw[6]&0x00FF)<<16) | pw[7]) );
    }
    
    error = PD_ifCheckParamValues(memAddrToDump, nWordsToDump>>2, smsDump);
    
    timetagFlag = *(((unsigned short* )PtrMcmd->PtrMCMD)+1) & TIMETAG_MASK ? TIMETAG_MCMD : IMMEDIATE_MCMD;
    MA_piDelBufferMCMD(PtrMcmd->PtrMCMD, timetagFlag);

    if ( error == PD_PARAM_VALUES_NO_ERROR )
    {
        if( Append_Next )
        {
            /* (1): append */
            if( DumpInfo->nWordsAvailable >= (nWordsToDump >> 1) )
            {
                /* appends the dump */
                /* The number of words is stored into 32 bit word unit  */
		*DumpInfo->pAppend     = (nWordsToDump<<6) | (pw[6]&0x00FF);
                *(++DumpInfo->pAppend) = pw[7];
                memcpy(++DumpInfo->pAppend , memAddrToDump, nWordsToDump);
                DumpInfo->pAppend += (nWordsToDump>>1);
                DumpInfo->nWordsAvailable -= ((nWordsToDump >> 1)+2);
            }
            else
            {
                error = HA_E2_DUMP_BUFFER_FULL;
            }
        }
        else /* (0): no append */
        {
             DumpInfo->pAppend = DumpBuff;
             DumpInfo->nWordsAvailable = PD_BUFFER_DUMP_MAX_SIZE;
             /* The number of words is stored into 32 bit word unit  */
             *DumpInfo->pAppend     = (nWordsToDump<<6) | (pw[6]&0x00FF);
             *(++DumpInfo->pAppend) = pw[7];             
             memcpy(++DumpInfo->pAppend , memAddrToDump, nWordsToDump);
             DumpInfo->pAppend += (nWordsToDump>>1);
             DumpInfo->nWordsAvailable -= ((nWordsToDump >> 1)+2);
        }
    }
    /* log in History Area*/
    // LOG_INFN HA_piLogHistoryEntry2(PtrMcmd->Type,error);
    /*@LOG Dump MCMD - error code */
    LU_INFN_LOG(LU_NORMAL_TRACE | LU_HA,LU_MASK(__FILEID__),__FILEID__,__LINE__,error);
}


/*****************************************************************************/
/* @Function: PD_ifCheckParamValues                                          */
/* @Purpose :                                                                */
/*   This function checks that the requested patch/dump address is inside    */
/*   the allowed range, RAM EEPROM respectively                              */
/*                                                                           */
/* @@                                                                        */
/* @Parameter Name      @Mode   @Description                                 */
/* memAddrStart         IN      memory address from which to start patch     */
/*                              or dump                                      */
/* nWords               IN      number of words (32 bit) to patch/dump       */
/* smsFlag              IN      Supervisor Memory Selection (RAM / EEPROM)   */
/* status_code          OUT     Return code                                  */
/* @@                                                                        */
/*****************************************************************************/
UWORD PD_ifCheckParamValues(UINT* memAddrStart, UWORD nWords, UWORD smsFlag)
{
  UWORD status;
  UINT  addrNotAlignedflag;

  status = PD_PARAM_VALUES_NO_ERROR;
  
  if( smsFlag == PD_RAM_PATCH )
  {
      /* checks if address is inside RAM space and/or buffer overflow */
      if( memAddrStart < (UINT*)PD_RAM_ADDR_START ||
          memAddrStart > (UINT*)PD_RAM_ADDR_END )
      {
          status = HA_E2_INVALID_ADDRESS;
      }
      else if( nWords >= PD_BUFFER_PATCH_MAX_SIZE ||
               memAddrStart + nWords - 1 > (UINT*)PD_RAM_ADDR_END )
           {
               status = HA_E2_INVALID_LENGTH;
           }
  }  
  else if ( smsFlag == PD_EEPROM_BANK0_PATCH )
  {
      /* The address must be 32-bit aligned                          */
      addrNotAlignedflag =((UINT)((UINT*)memAddrStart) & 0x00000003);
      /* checks if address is inside EEPROM space and/or buffer overflow */
      if( memAddrStart < (UINT*)PD_EEPROM_BANK0_ADDR_START ||
          memAddrStart > (UINT*)PD_EEPROM_BANK0_ADDR_END   ||
	  /* The address must be 32-bit aligned                          */
	  addrNotAlignedflag ) 
      {
          status = HA_E2_INVALID_ADDRESS;
      }
      else if( nWords >= PD_BUFFER_PATCH_MAX_SIZE                      ||
               memAddrStart + nWords - 1 > (UINT*)PD_EEPROM_BANK0_ADDR_END )
           {
               status = HA_E2_INVALID_LENGTH;
           }
  }
  else if ( smsFlag == PD_EEPROM_BANK1_PATCH )
  {
      /* The address must be 32-bit aligned                          */
      addrNotAlignedflag =((UINT)((UINT*)memAddrStart) & 0x00000003);
      /* checks if address is inside EEPROM space and/or buffer overflow */
      if( memAddrStart < (UINT*)PD_EEPROM_BANK1_ADDR_START ||
          memAddrStart > (UINT*)PD_EEPROM_BANK1_ADDR_END   ||
	  /* The address must be 32-bit aligned                          */
	  addrNotAlignedflag )
      {
          status = HA_E2_INVALID_ADDRESS;
      }
      else if( nWords >= PD_BUFFER_PATCH_MAX_SIZE                       ||
               memAddrStart + nWords - 1 > (UINT*)PD_EEPROM_BANK1_ADDR_END )
           {
               status = HA_E2_INVALID_LENGTH;
           }
  }
  else
      status = HA_E2_INVALID_ADDRESS;

  return status;
}


/*****************************************************************************/
/* @Function: PD_ifEEPROMWrite                                               */
/* @Purpose :                                                                */
/*  This function writes a specified number of words from a source buffer    */
/*  to an EEPROM memory address. When a boundary is reached the process of   */
/*  writing is suspended for 10 milliseconds.                                */
/*                                                                           */
/* @@                                                                        */
/* @Parameter Name      @Mode   @Description                                 */
/* dstAddr              IN      write destination address                    */
/* sourceAddr           IN      read source address                          */
/* nWords32Bit          IN      number of words (32 bit) to be written       */
/* @@                                                                        */
/*****************************************************************************/
void PD_ifEEPROMWrite(void* dstAddr, void* sourceAddr, UINT nWords32Bit )
{
unsigned int   level;
UINT           boundaryFlag;
UINT           boundery;
UINT           i;
    
    /* Enable EEPROM writing by programming CRIMEA register     */    
    CD_EEPROM_WRITE_ENABLE;
    while ( nWords32Bit > 0 ) 
    {
        
        boundaryFlag =FALSE;
        /* Find number of words until the boundary page         */
        for (i=0; i<PD_EEPROM_LENGHT && !boundaryFlag && nWords32Bit>0; i++)
        {
            boundery =((UINT)((UINT*)dstAddr+i) & 0x000001FF);
	    if (boundery == PD_BOUNDARY_EEPROM)
            {
                boundaryFlag =TRUE;
            }	
            nWords32Bit--;
        }
        /* Write specified number of words into EEPROM          */
        PD_ifCopyRamToEEprom((UINT*)sourceAddr,(UINT*)dstAddr,i);
        /* Increment destination and source address             */
        (UINT*)dstAddr     +=i;
        (UINT*)sourceAddr  +=i;
    }
    /* Disable EEPROM writing by programming CRIMEA register    */
    CD_EEPROM_WRITE_DISABLE;
}




/*****************************************************************************/
/* @Function: PD_ifCopyRamToEEprom                                           */
/* @Purpose :                                                                */
/*  This function writes a specified number of words from a source buffer    */
/*  a source buffer to an EEPROM memory address. The number of written words */
/*  into the EEPROM must not exceed the page boundary. At the end of the     */
/*  writing procedure the task is suspended for 10 milliseconds.             */
/*                                                                           */
/* @@                                                                        */
/* @Parameter Name      @Mode   @Description                                 */
/* Dest                 IN      write destination address                    */
/* Source               IN      read source address                          */
/* Len                  IN      number of words (32 bit) to be written       */
/* @@                                                                        */
/*****************************************************************************/
void PD_ifCopyRamToEEprom(UINT* Source, UINT* Dest, UINT Len)
{
  unsigned int c;
  unsigned int level=0;
  UINT *ss=Source, *sd=Dest;

  /* added for safe: if the block is axactly the same, do nothing : */
  for (c=0 ; c<Len && level==0; c++, Source++,Dest++)
    {
      level += (*Dest != *Source);
    }
  if(level==0)
    return;

  Dest=sd;
  Source=ss;

  /* Disable interrupts in order to don't break off       */
  /* the EEPROM write procedure                           */
  level =sparc_disable_interrupts();
  /* Move data from source to destination                 */
  for (c=0 ; c<Len; c++, Source++,Dest++)
    {
      *Dest =*Source;
    }
  /* Enable interrupts                                    */
  sparc_enable_interrupts(level);
  /* Suspend task to starting internal EEPROM writing     */
  if(rtems_interrupt_is_in_progress())
    CM_Suspend_Dummy_Loop(13);
  else
    OS_piTaskSuspend(12);
}

