/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************/
/** \file mfs_i2c.c
 **
 ** A detailed description is available at
 ** @i2ck I2cGroup I2C Module description @endi2ck
 **
 ** History:
 **    - 2014-10-24  1.0  MA  Initial version for Traveo I2C Interface 
 **    - 2014-11-25  1.1  PDL Version including interrupts handling and Rx/Tx fifo  
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "pdl.h"

#if defined(PDL_PERIPHERAL_I2C_ACTIVE)

/**
 *****************************************************************************
 ** \addtogroup I2cGroup
 *****************************************************************************/
/** @{ */

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

#define I2C_READ     0x01       // Read Access
#define I2C_WRITE    0x00       // Write Access

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/**
 *****************************************************************************
 ** \brief Data type for holding internal data for callbacks needed
 **
 ** This struct is used to store the interrupt callback function for the I2C.
 *****************************************************************************/
typedef struct stc_i2c_intern_data
{
    func_ptr_t       pfnStopConditionCallback ;
    func_ptr_t       pfnRepeatedStartCallback ;
    func_ptr_t       pfnBusErrorCallback;
    func_ptr_t       pfnArbitrationLostCallback;
    func_ptr_t       pfnReservedAddressDetectedCallback;
    func_ptr_t       pfnNACKCallback;
    func_ptr_t       pfnTransmissionFifoOverRunCallback;
    func_ptr_t       pfnReceptionFifoUnderRunCallback;
    func_ptr_t       pfnReceptionFifoFullCallback ;  
    boolean_t        bRead;
    uint8_t          u8SlaveAddress;
    unsigned char    m_readBuffer[16];
    unsigned char    m_writeBuffer[16];
} stc_i2c_intern_data_t;



/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/

//Loop Counter: Will hold the count number of times each a interrupt has been called
static uint32_t    m_u32Index = 0;

//hold the number of bytes to write
static uint8_t    m_u8DataLengthTx = 0;

//hold the number of bytes to read
static uint8_t    m_u8DataLengthRx = 0;

//holds the address where to read from
static uint8_t    m_u8ReadAddress = 0;

// Looop counter
static uint32_t    u32count = 0;

// Buffer to hold read values  
static uint32_t    m_32ReadValuesFifo[16];

//Numbre of bytes to read
static uint32_t    m_u32ReadBytes = 0;

/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/

static void I2cIrqHandler(volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                          stc_i2c_intern_data_t* pstcI2cInternData);

static void I2cIrqHandlerTx(volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                            stc_i2c_intern_data_t* pstcI2cInternData);

static void I2cIrqHandlerRx(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                            stc_i2c_intern_data_t *pstcI2cInternData);


/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

#include "mfs_i2c_generated.c"
#include "string.h"

/**
 *****************************************************************************
 ** \brief ISR callback for I2C status and error interrupt.
 **
 ** This handler is called by the I2C ISR whenever a I2C triggers
 ** status and error interrupt.
 ** It in return calls the callback function that has been given
 ** during I2C initialization (see I2c_Init() and stc_i2c_config_t) and clears
 ** the interrupt flags of the I2C.
 **
 ** \param [in] pstcI2c           I2C unit instance that caused the interrupt.
 ** \param [in] pstcI2cInternData Internal data associated with the I2C instance
 **
 *****************************************************************************/
static void I2cIrqHandler( volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                          stc_i2c_intern_data_t* pstcI2cInternData)
{
    // Check if a Stop condition interrupt is raised
    if ( pstcI2c->unIBSR.stcField.u1SPC == 1 )
    {
        // clear interrupt flag
        pstcI2c->unIBSRC.stcField.u1SPCC= 1;
    
        // Call I2C callback function provided during configuration
        if ( pstcI2cInternData->pfnStopConditionCallback != NULL )
        {
            pstcI2cInternData->pfnStopConditionCallback() ;
        }
    }
  
    // Check if a Repeated Start condition interrupt is raised
    if ( pstcI2c->unIBSR.stcField.u1RSC == 1 )
    {
        // clear interrupt flag 
        pstcI2c->unIBSRC.stcField.u1RSCC= 1;
      
        // Call I2C callback function 
        if ( pstcI2cInternData->pfnRepeatedStartCallback != NULL )
        {
            pstcI2cInternData->pfnRepeatedStartCallback() ;
        }
    }
    
    // Check if a Error/Status interrupt is raised
    if ( pstcI2c->unIBCR.stcField.u1INT == 1 )
    {
        // clear interrupt flag 
        pstcI2c->unIBCRC.stcField.u1INTC= 1;
      
        // Check and Call concerned callback function 
        if (  pstcI2c->unIBCR.stcField.u1BER == 1 && pstcI2cInternData->pfnBusErrorCallback != NULL ) // Check and Call I2C Bus Error callback function
        {
            pstcI2cInternData->pfnBusErrorCallback() ;
        }
        else if( pstcI2c->unIBSR.stcField.u1AL == 1 && pstcI2cInternData->pfnArbitrationLostCallback != NULL )// Check and Call I2C Arbitration Lost callback function 
        {
            pstcI2cInternData->pfnArbitrationLostCallback() ;
        }        
        else if ( pstcI2c->unIBSR.stcField.u1RSA == 1 &&  pstcI2cInternData->pfnReservedAddressDetectedCallback != NULL )// Check and Call I2C Reserved address detection callback function 
        {
            pstcI2cInternData->pfnReservedAddressDetectedCallback() ;
        }         
        else if ( pstcI2cInternData->pfnNACKCallback != NULL )// Check and Call I2C NACK received callback function 
        {
            pstcI2cInternData->pfnNACKCallback() ;
        }
    }
    
} /* I2cIrqHandler */


/**
 *****************************************************************************
 ** \brief ISR callback for I2C Transmission interrupt.
 **
 ** This handler is called by the I2C ISR whenever a I2C triggers
 ** Transmission interrupt.
 **
 ** \param [in] pstcI2C           I2C unit instance that caused the interrupt.
 ** \param [in] pstcI2cInternData Internal data associated with the I2C instance
 **
 *****************************************************************************/
static void I2cIrqHandlerTx(volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                            stc_i2c_intern_data_t* pstcI2cInternData)
{
    // Check if Transmission register is empty is raised 
    if ( pstcI2c->unSSR.stcField.u1TDRE == 1 )
    {
        // clear interrupt flag 
        //Writting to TDR will clear interupt
    
        if((1 == pstcI2c->unIBCR.stcField.u1BER)|| //Check for Bus Error
           (1 == pstcI2c->unIBSR.stcField.u1RSA)|| //Check for Reserved start address is detected
           (1 == pstcI2c->unIBSR.stcField.u1AL)||  //Check if Arbitration is lost
           (1 == pstcI2c->unIBSR.stcField.u1RACK)) // and Check if acknowldge received 
        {
            //Error: Cannt Transmit Data Anymore
        }
        else  //Transmit the buffer
        {
            Mfs_I2c_Write(pstcI2c,pstcI2cInternData->m_writeBuffer[m_u32Index]);
            m_u32Index++;
            if( m_u8DataLengthTx+2==m_u32Index )// If Data Transmission completed + for First Address Byte
            {
                pstcI2c->unSMRC.stcField.u1TIEC=1;//Disable Interupt
                m_u32Index =0;// for again use by rxhandler or txhandler
            }   
        }
    }
    
    // Check if Transmission FIFO overrun interrupt is raised
    if ( pstcI2c->unESR.stcField.u1TXOVR == 1 )
    {
        // clear interrupt flag
        pstcI2c->unESRC.stcField.u1TXOVRC= 1;
      
        // Call I2C callback function 
        if ( pstcI2cInternData->pfnTransmissionFifoOverRunCallback != NULL )
        {
            pstcI2cInternData->pfnTransmissionFifoOverRunCallback() ;
        }
    }
} /* I2cIrqHandlerTx */


/**
 *****************************************************************************
 ** \brief ISR callback for I2C Reception interrupt.
 **
 ** This handler is called by the I2C ISR whenever a I2C triggers
 ** Reception interrupt.
 **
 ** \param [in] pstcI2C           I2C unit instance that caused the interrupt.
 ** \param [in] pstcI2cInternData Internal data associated with the I2C instance.
 ** 
*****************************************************************************/
static void I2cIrqHandlerRx(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                            stc_i2c_intern_data_t *pstcI2cInternData)
{
    if(pstcI2c->unFCR0.stcField.u1FE2==TRUE)//FIFO Enabled
    {
        //Clear the interrupt flag by reading fifo buffer
        for (u32count=0; u32count< m_u32ReadBytes; u32count++)
        {
            m_32ReadValuesFifo[u32count]=pstcI2c->unRDR.u8Register;
        }
    
        // Check and call if callback is provided
        if(pstcI2cInternData->pfnReceptionFifoFullCallback != NULL)
        {
            pstcI2cInternData->pfnReceptionFifoFullCallback();
        }
    }
    else
    {
        // clear interrupt flag 
        // Reading RDR will clear interupt
             
        //Check errors
        if((1 == pstcI2c->unIBCR.stcField.u1BER)||//Check for Bus Error
           (1 == pstcI2c->unIBSR.stcField.u1RSA)||//Check for Reserved start address is detected
           (1 == pstcI2c->unIBSR.stcField.u1AL))  //Check if Arbitration is lost
        {
            //Error: Cannt Receive Data Anymore
        }
        else//Receive data
        {
            if(0==m_u32Index) // If Reception Started
            {
                // Release the Bus
                Mfs_I2c_Stop(pstcI2c);
          
                // start Reception phase
                // 1010000 for the 24LC22A.
                Mfs_I2c_Start(pstcI2c, pstcI2cInternData->u8SlaveAddress | I2C_WRITE);
          
                // Address where to read from
                Mfs_I2c_Write(pstcI2c, m_u8ReadAddress);
          
                // Restart, with READ comand
                Mfs_I2c_Continue(pstcI2c, pstcI2cInternData->u8SlaveAddress | I2C_READ);   
         
                //Save the read data: First Byte
                Mfs_I2c_Read(pstcI2c,&pstcI2cInternData->m_readBuffer[m_u32Index]);
      
                //Increase the loop counter
                m_u32Index++;
            }
            else if(m_u32Index==m_u8DataLengthRx)  //If Reception Completed
            {
                //Reception of data is completed: Disable Interupt
                pstcI2c->unSMRC.stcField.u1RIEC=1;
       
                //For Last read No Acknowledge is to be sent
                Mfs_I2c_ReadLast(pstcI2c,&pstcI2cInternData->m_readBuffer[m_u32Index]);
       
                //Set the counter to 0 for reuse
                m_u32Index=0;
            }
            else  // Receive data
            {
                // Read the data
                Mfs_I2c_Read(pstcI2c,&pstcI2cInternData->m_readBuffer[m_u32Index]);
            
                //Increase the loop counter
                m_u32Index++;
            }
        }
    }
} /* I2cIrqHandlerRx */

/**
 *****************************************************************************
 ** \brief Get read values
 **
 ** This Function Reads back the values which were read using reception fifo
 ** or interupts.
 ** 
 ** \pre must be called after reception interupt ISR has completed its execution.
 **
 ** \param [in]  pstcI2c        Pointer to I2C instance register area
 ** \param [in] cReadBuffer     Array to return read values.
 **
 ** \retval Ok                    Values read successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL ( pstcI2c is not available or enabled)
 **
 *****************************************************************************/
en_result_t Mfs_I2c_GetReadValues(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                                  unsigned char cReadBuffer[])
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    if( pstcI2c->unFCR0.stcField.u1FE2==1)//if reception fifo values to be read
    {
        // Copy values
        for (u32count = 0; u32count < m_u32ReadBytes ; u32count++)
        {
            cReadBuffer[u32count]= m_32ReadValuesFifo[u32count];
        }
    }
    else//if interupt values to be read
    {
        // Pointer to the internal data structure
        stc_i2c_intern_data_t* pstcInternData ;
  
        // Get pointer to internal data
        pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
        //check for NULL pointer
        if ( pstcInternData == NULL )
        {
            return ErrorInvalidParameter ; // The pstcI2c that was passed is not available or not enabled 
        }
  
        // Copy values
        for (uint32_t Index = 0; Index < m_u8DataLengthRx+1 ; Index++)
        {
            cReadBuffer[Index]= pstcInternData->m_readBuffer[Index];
        }
    }
    return Ok;

}/* Mfs_I2c_getReadValues */

/**
 *****************************************************************************
 ** \brief Initialisation of a I2C module.
 **
 ** This Function initialises the I2C according to the Options setup in the
 ** passed Config Struct. Several Checkings are done before that and an error
 ** is returned if invalid Modes are requested.
 **
 ** The required timing settings for data rate are calculated automatically
 ** with respect to the current peripheral clock.
 **
 ** \param [in]  pstcI2c        Pointer to I2C instance register area
 ** \param [in]  pstcConfig     I2C module configuration. See #stc_i2c_config_t.
 **
 ** \retval Ok                    Initializiation of I2C module successfully done.
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcConfig == NULL
 **         - pstcInternData == NULL ( pstcI2c is not available or enabled)
 **        
 *****************************************************************************/
 en_result_t Mfs_I2c_Init(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                          stc_i2c_config_t *pstcConfig)
{
    // Check if pointers are valid 
    if ((pstcI2c == NULL)||
        (pstcConfig == NULL))
    {
        return ErrorInvalidParameter;
    }
    
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ;
   
    // Get pointer to internal data  
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
   
    //check for NULL pointer 
    if ( pstcInternData == NULL )
    {
        // The pstcI2c that was passed is not available or not enabled
        return ErrorInvalidParameter ;
    }
    
    //Loop counter  
    uint32_t u32Index = 0;
   
    //Preset local register variable to zero   
    un_cpg_mfsn_i2c_ibcr_t    unIBCR    = { 0 };
    un_cpg_mfsn_i2c_fcr0s_t   unFCROS   = { 0 };
    un_cpg_mfsn_i2c_ibcrs_t   unIBCRS   = { 0 };
    un_cpg_mfsn_i2c_ibcrc_t   unIBCRC   = { 0 };
    un_cpg_mfsn_i2c_smrs_t    unSMRS    = { 0 };
    un_cpg_mfsn_i2c_smr_t     unSMR     = { 0 };
    un_cpg_mfsn_i2c_smrc_t    unSMRC    = { 0 };
    un_cpg_mfsn_i2c_ibsrc_t   unIBSRC   = { 0 };
    un_cpg_mfsn_i2c_ssrc_t    unSSRC    = { 0 };         
    un_cpg_mfsn_i2c_ismk_t    unISMK    = { 0 };	
    un_cpg_mfsn_i2c_bgr_t     unBGR     = { 0 };        
    un_cpg_mfsn_i2c_isba_t    unISBA    = { 0 };
    un_cpg_mfsn_i2c_ssr_t     unSSR     = { 0 };
    un_cpg_mfsn_i2c_ibsr_t    unIBSR    = { 0 };
    un_cpg_mfsn_i2c_ssrs_t    unSSRS    = { 0 };
    
    // Select I2C mode
    unSMR.stcField.u3MD        =4;
    
    // Disable I2C 
    unISMK.stcField.u1EN       = 0;
   
    // Slave address enable bit
    unISBA.stcField.u1SAEN     = pstcConfig->bSlaveAddressEnable;
   
    // I2C set as Slave
    unIBCRS.stcField.u1MSSS    = 0;
   
    // Operation flag
    unIBCR.stcField.u1ACT=0;
   
    // Data byte acknowledge enable/disabled
    unIBCRS.stcField.u1ACKES   =pstcConfig->bAcknowledgeEnable;
   
    // Wait after acknowledge
    unIBCRS.stcField.u1WSELS   =pstcConfig->bWaitSelect;
   
    // Copy provided write values buffer to internal write values holding buffer   
    for(u32Index=0; u32Index<6;u32Index++)
    {
        pstcInternData->m_writeBuffer[u32Index]=pstcConfig->m_writeBuffer[u32Index];
    }   
          
    // DMA mode disabled
    if(pstcConfig->bDmaModeEnable==TRUE)
    {
        unSSRS.stcField.u1DMAS      = 1;
    }
    else
    {
        unSSRC.stcField.u1DMAC      = 1;
    }
   
    /*Baud rate calculation*/
    uint32_t      u32ReloadValue;
   
    // TODO: Based on the i2c instance we have to use different clocks for baudrate calculation 
    u32ReloadValue     = SysCtrl_GetDistributedClockFrequencyHz(SysCtrlDistributedClockLCP0A);
   
    // Calc reload value based on data rate set 
    u32ReloadValue /= pstcConfig->u32DataRate;
   
    // Check if reload value is 0 (to avoid underflow) 
    if (u32ReloadValue == 0)
    {
        return ErrorInvalidParameter;
    }
    
    //Set baud rate generation reload register 
    unBGR.u16Register = (uint16_t)u32ReloadValue;
   
    // Repeat start condition check indicator
    unIBSRC.stcField.u1RSCC     = 1;
   
    // Stop condition check indicator
    unIBSRC.stcField.u1SPCC     =1;
   
    //Disable FIFOs
    pstcI2c->unFCR0C.stcField.u1FE1C=1;// disable FIFO1
    pstcI2c->unFCR0C.stcField.u1FE2C=1;// disable FIFO2
   
    // Store the callback that shall be called within the interrupt routine in the internal data structure
    pstcInternData->pfnRepeatedStartCallback              =    pstcConfig->pfnRepeatedStartCallback ;          
    pstcInternData->pfnStopConditionCallback              =    pstcConfig->pfnStopConditionCallback;
    pstcInternData->pfnBusErrorCallback                   =    pstcConfig->pfnBusErrorCallback;
    pstcInternData->pfnArbitrationLostCallback            =    pstcConfig->pfnArbitrationLostCallback;
    pstcInternData->pfnReservedAddressDetectedCallback    =    pstcConfig->pfnReservedAddressDetectedCallback;
    pstcInternData->pfnNACKCallback                       =    pstcConfig->pfnNACKCallback;
    pstcInternData->pfnTransmissionFifoOverRunCallback    =    pstcConfig->pfnTransmissionFifoOverRunCallback;
    pstcInternData->pfnReceptionFifoUnderRunCallback      =    pstcConfig->pfnReceptionFifoUnderRunCallback;
    pstcInternData->pfnReceptionFifoFullCallback          =    pstcConfig->pfnReceptionFifoFullCallback;

    //Store the slave address
    pstcInternData->u8SlaveAddress    =    pstcConfig->u8SlaveAddress;
    
    //Interrupt flag clear
    //Disable Transmission Interupt
    unSMRC.stcField.u1TIEC=1;
    
    //Disable Reception Interupt
    unSMRC.stcField.u1RIEC=1;
    
    //Disable Repeated start/stop condition IRQ 
    unIBCRC.stcField.u1CNDEC  =1;
   
    //Disable Transmission/Reception IRQ 
    unIBCRC.stcField.u1INTEC  =1;
   
    //Disable Transmission/Reception IRQ flag
    unIBCRC.stcField.u1INTC     = 1;
   
    //Disable Transmission bus idle IRQ 
    unSSRC.stcField.u1TBIEC     = 1;
 
    // now setup HW register(s)
    pstcI2c->unSMR.u8Register          =  unSMR.u8Register;
    pstcI2c->unBGR.u16Register         =  unBGR.u16Register;
    pstcI2c->unISMK.u8Register         =  unISMK.u8Register;
    pstcI2c->unISBA.u8Register         =  unISBA.u8Register;
    pstcI2c->unSMRS.u8Register         =  unSMRS.u8Register;  
    pstcI2c->unSMRC.u8Register         =  unSMRC.u8Register;
    pstcI2c->unIBCR.u8Register         =  unIBCR.u8Register;
    pstcI2c->unIBCRS.u8Register        =  unIBCRS.u8Register;
    pstcI2c->unIBCRC.u8Register        =  unIBCRC.u8Register;
    pstcI2c->unIBSRC.u8Register        =  unIBSRC.u8Register;
    pstcI2c->unSSRC.u8Register         =  unSSRC.u8Register;
    pstcI2c->unSSR.u8Register          =  unSSR.u8Register;    
    pstcI2c->unSSRS.u8Register         =  unSSRS.u8Register;
   
    return Ok;
   
} /* Mfs_I2c_Init */

/**
 *****************************************************************************
 ** \brief Start of a I2C module.
 **      
 ** This Function Starts the I2C Commincation with Slave Addressed. A Slave
 ** Address is output with the start condition and acknowlege from the
 ** slave ia expected. 
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 ** \param [in]  ui7SlaveAddress        I2C Slave Address 
 **
 ** \retval Ok                          Communication set up successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL ( pstcI2c is not available or enabled)
 ** 
*****************************************************************************/
en_result_t Mfs_I2c_Start(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                          uint8_t u8SlaveAddress)
{
    un_cpg_mfsn_i2c_rdr_t unRDR={0};
  
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ; 
  
    // Get pointer to internal data 
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
    //check for NULL pointer 
    if ( pstcInternData == NULL )
    {
        // The pstcI2C that was passed is not available or not enabled 
        return ErrorInvalidParameter ;
    }

    do
    {
        // Enable I2C
        pstcI2c->unISMK.stcField.u1EN = 1;
    
        //Set Slave Address
        unRDR.u8Register=u8SlaveAddress|0;
        pstcI2c->unRDR.u8Register= unRDR.u8Register;
    
        // set master mode and set start condition  
        pstcI2c->unIBCRS.stcField.u1MSSS=1;
    
        // look if transfer is in process
        while(0 == pstcI2c->unIBCR.stcField.u1INT)
        {
            PDL_WAIT_LOOP_HOOK();
        }
    } while (1 == pstcI2c->unIBCR.stcField.u1BER);   // retry if Bus-Error detected        
  
    // no acknowledge means device not ready    
    while(1 == pstcI2c->unIBSR.stcField.u1RACK)
    {
        // try restart (= continue)  
        pstcI2c->unIBCRS.stcField.u1ACTS = 1;  //  Generate the repeated start condition.
    
        // wait that transfer is finished
        while(0 == pstcI2c->unIBCR.stcField.u1INT)
        {
            PDL_WAIT_LOOP_HOOK();
        }
    }
  
    return Ok;
  
} /* Mfs_I2c_Start */

/**
 *****************************************************************************
 ** \brief Write of a I2C module.
 **
 ** This Function Writes a provided byte to the Slave .A acknowlege from the
 ** slave is expected. 
 **
 ** \pre Mfs_I2c_Init() and Mfs_I2c_Start() must have called
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 ** \param [in]  cValue                 Byte to be written to slave
 **
 ** \retval Ok                          Byte written successfully
 ** \retval ErrorInvalidParameter If following conditions is met:
 **         - pstcI2c == NULL
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_Write(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                          unsigned char cValue)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
   
    // load data or address in to register
    pstcI2c->unRDR.u8Register = cValue;                  
    
    // clear transfer end intrerupt flag
    pstcI2c->unIBCRC.stcField.u1INTC = 1;
    
    // look if transfer is in process
    while (0 ==  pstcI2c->unIBCR.stcField.u1INT)          
    {
        PDL_WAIT_LOOP_HOOK();
    }  
    
    // wait for Acknowledge
    Mfs_I2c_Acknowlegde(pstcI2c);            
    
    return Ok;
            
} /* Mfs_I2c_Write */

/**
 *****************************************************************************
 ** \brief Write Sequence to I2C module.
 **
 ** This Function Writes a provided data array in a sequence to a Slave using 
 ** Transmission interupts.
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                 Pointer to I2C instance register area
 ** \param [in]  u8SlaveAddress         Address of a slave
 ** \param [in]  u8WriteLocation         Base address where to write
 ** \param [in]  u8Data                  Data Array to containing write values
 ** \param [in]  u8DataLength            Number of bytes to be written
 **
 ** \retval Ok                          Bytes written successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL( pstcI2c is not available or enabled)
 **
 *****************************************************************************/
en_result_t Mfs_I2c_WriteSequence( volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                                   uint8_t  u8SlaveAddress,
                                   uint8_t  u8WriteLocation,
                                   uint8_t  u8Data[],
                                   uint8_t  u8DataLength)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    //loop counter
    uint32_t Index = 0;
    
    //Assign data length to static variable
    m_u8DataLengthTx=u8DataLength;
   
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ; 
  
    // Get pointer to internal data ...
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
    //check for NULL pointer */
    if ( pstcInternData == NULL )
    {
        // The pstcI2C that was passed is not available or not enabled */
        return ErrorInvalidParameter ;
    }
    
    //Assign write location to first element of tranmission buffer
    pstcInternData->m_writeBuffer[Index]=u8WriteLocation;
    
    // Copy provided write values buffer to internal write values holding buffer   
    for(Index=1; Index<u8DataLength+2;Index++)
    {
        pstcInternData->m_writeBuffer[Index]=u8Data[Index-1];
    }   
    
    // start transmission phase
    Mfs_I2c_Start(pstcI2c, u8SlaveAddress | I2C_WRITE);
     
    //Enable Interupt
    Mfs_I2c_EnableInterupt(pstcI2c,FALSE,FALSE,TRUE);
     
    // wait until transmission ready and bus is free
    Mfs_I2c_Acknowlegde(pstcI2c);
             
    //Stop: Release Bus
    Mfs_I2c_Stop(pstcI2c);
  
    return Ok;

} /* Mfs_I2c_WriteSequence */

/**
 *****************************************************************************
 ** \brief Sequence Read of a I2C module.
 **
 ** This Function reads a sequence of bytes from a Slave from provided address using 
 ** reception interupts and return them in au8Data[].
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 ** \param [in]  u8SlaveAddress         Address of a slave
 ** \param [in]  u8ReadLocation         Base address where to read from
 ** \param [in]  au8Data                Data Array to return read values
 ** \param [in]  u8DataLength           Number of bytes to be read
 **
 ** \retval Ok                          Byte written successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL( pstcI2c is not available or enabled)
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_ReadSequence( volatile stc_cpg_mfsn_i2c_t* pstcI2c,
                                  uint8_t  u8SlaveAddress,
                                  uint8_t  u8ReadLocation,
                                  uint8_t  u8Data[],
                                  uint8_t  u8DataLength)
{
    //dummy pointer
    unsigned char cDummyValue;
    
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // Assign data length to static variable
    m_u8DataLengthRx=u8DataLength;
   
    // Assign Read location to static variable
    m_u8ReadAddress= u8ReadLocation;
    
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ; 
  
    // Get pointer to internal data
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
    //check for NULL pointer 
    if ( pstcInternData == NULL )
    {
        // The pstcI2C that was passed is not available or not enabled 
        return ErrorInvalidParameter ;
    }
  
    //Start Reception Phase
    Mfs_I2c_Start(pstcI2c, u8SlaveAddress | I2C_READ);
     
    //Enable Interupt
    Mfs_I2c_EnableInterupt(pstcI2c,FALSE,TRUE,FALSE);
     
    //Generate Interupt
    Mfs_I2c_ReadLast(pstcI2c,&cDummyValue);
     
    //Stop: Release Bus
    Mfs_I2c_Stop(pstcI2c);
    
    //Get the read values back
    Mfs_I2c_GetReadValues(pstcI2c,u8Data);
   
    return Ok;

}/* Mfs_I2c_ReadSequence */


/**
 *****************************************************************************
 ** \brief Acknowledge
 **
 ** This Function provides an Acknowledge from the Slave.
 **
 ** \pre Mfs_I2c_Init() must be called
 ** \pre read or write operation is performed to slave
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 **
 ** \retval Ok                          Acknowledged successfully
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_Acknowlegde(volatile stc_cpg_mfsn_i2c_t *pstcI2c)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // no anwser from slave, program stucks her
    while(1 == pstcI2c->unIBSR.stcField.u1RACK)    
    {
        PDL_WAIT_LOOP_HOOK();
    }
    
    return Ok;
} /* Mfs_I2c_Acknowlegde */

/**
 *****************************************************************************
 ** \brief Stop I2c
 **
 ** This Function Stops the communication setup between master and Slave.
 ** I2C Bus is released.
 **
 ** \pre Mfs_I2c_Init() and Mfs_I2c_Start() must be called
 ** 
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 **
 ** \retval Ok                          Communication Stopped successfully
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_Stop(volatile stc_cpg_mfsn_i2c_t *pstcI2c)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // wait that transfer is finished
    while (0 == pstcI2c->unIBCR.stcField.u1INT)          
    {
        PDL_WAIT_LOOP_HOOK();
    }  
      
    // release stop condition
    pstcI2c->unIBCRC.stcField.u1MSSC = 1;
    
    // clear transfer end interrupt flag                     
    pstcI2c->unIBCRC.stcField.u1INTC = 1;  
    
    // wait till bus free
    while(1 == pstcI2c->unIBSR.stcField.u1BB)       
    {
        PDL_WAIT_LOOP_HOOK();
    }
    
    return Ok;

} /* Mfs_I2c_Stop */

/**
 ******************************************************************************
 ** \brief Read I2c
 **
 ** This Function Reads a byte from the Slave. For Sequential Data Read Master
 ** needs to send Acknowledge for the every byte to indicate successfull reception 
 ** of data until the last byte. For every byte read acknowledge must be sent.
 **
 ** \pre Mfs_I2c_Init() and Mfs_I2c_Start() must be called
 ** 
 ** \param [in]  pstcI2c                        Pointer to I2C instance register area
 **
 ** \retval pstcI2c->unRDR.u8Register           Byte Read         
 ** \retval ErrorInvalidParameter If
 **         - pstcI2c == NULL
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_Read(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                         unsigned char* cReadValue)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // Acknowledge has to send
    pstcI2c->unIBCRS.stcField.u1ACKES = 1;    

    // clear transfer end interrupt flag
    pstcI2c->unIBCRC.stcField.u1INTC   = 1;         
  
    // wait that transfer is finished
    while (0 == pstcI2c->unIBCR.stcField.u1INT)  
    {
        PDL_WAIT_LOOP_HOOK();
    }  
    
    // read received data out
    *(cReadValue) = pstcI2c->unRDR.u8Register;
    
    return Ok;   
 
} /* Mfs_I2c_Read */


/**
 *****************************************************************************
 ** \brief Continue
 **
 ** This Function generates the repeated start condition once communication is already 
 ** started without releasing I2C Bus.
 **
 ** \pre Mfs_I2c_Init() and Mfs_I2c_Start() must be called
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 ** \param [in]  u8SlaveAddress        Slave Address
 **
 ** \retval Ok                          Repeated start condition generated successfully.
  ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **        
 *****************************************************************************/
en_result_t Mfs_I2c_Continue(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                             uint8_t u8SlaveAddress)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
  
    // slave_address is sent out with start condition     
    pstcI2c->unRDR.u8Register = u8SlaveAddress;  
    
    // restart (= continue)
    pstcI2c->unIBCRS.stcField.u1ACTS=1;
    
    // wait that transfer is finished
    while (0 == pstcI2c->unIBCR.stcField.u1INT)          
    {
       PDL_WAIT_LOOP_HOOK();
    }

    return Ok;
} /* Mfs_I2c_Continue */


/**
 *****************************************************************************
 ** \brief Last Read
 **
 ** This Function Reads a byte from the Slave. For Sequential Data Read Master
 ** needs not to send Acknowledge for the last byte to indicate end of reception.
 **
 ** \pre Mfs_I2c_Init(), Mfs_I2c_Start() and Mfs_I2c_Read() must be called
 ** 
 ** \param [in]  pstcI2c                        Pointer to I2C instance register area
 **
 ** \retval pstcI2c->unRDR.u8Register           Byte Read  
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **
 *****************************************************************************/
en_result_t Mfs_I2c_ReadLast(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                             unsigned char* cReadValue)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // no acknowledge has to be send after last byte
    pstcI2c->unIBCRC.stcField.u1ACKEC = 1;
  
    // clear transfer end interrupt flag
    pstcI2c->unIBCRC.stcField.u1INTC   = 1;
  
    // wait that transfer is finished
    while (0 == pstcI2c->unIBCR.stcField.u1INT)  
    {
        PDL_WAIT_LOOP_HOOK();
    }

    // read received data out
    *(cReadValue) = pstcI2c->unRDR.u8Register;
    
    return Ok;                       
  
} /* Mfs_I2c_ReadLast */


/**
 *****************************************************************************
 ** \brief Enable Interupt
 **
 ** This Function Enables interupts if corresponding ISR are provided to 
 ** handle at the time of configuration.
 **
 ** \param [in]  pstcI2c                   Pointer to I2C instance register area
 ** \param [in]  bEnableStatus             Status Interupt Enable requested
 ** \param [in]  bEnableRx                 Reception Interupt Enable requested     
 ** \param [in]  bEnableTx                 Transmission Interupt Enable requested      
 ** \retval Ok                             Intrupt Enabled successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL
 **
 *****************************************************************************/
en_result_t Mfs_I2c_EnableInterupt(volatile  stc_cpg_mfsn_i2c_t *pstcI2c,
                                   boolean_t bEnableStatus,
                                   boolean_t bEnableRx, 
                                   boolean_t bEnableTx)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
  
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ; 
  
    // Get pointer to internal data ...
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
    //check for NULL pointer */
    if ( pstcInternData == NULL )
    {
        // The pstcI2C that was passed is not available or not enabled */
        return ErrorInvalidParameter ;
    }
    
    //Enable interupts
    if(bEnableStatus == TRUE)//Check if Status Interupt are requested  
    {
        if (( pstcInternData->pfnRepeatedStartCallback != NULL )||
            (pstcInternData->pfnStopConditionCallback != NULL))
        {
             // Enable interrupt
             pstcI2c->unIBCRS.stcField.u1CNDES = 1;
        }
        else if((pstcInternData->pfnBusErrorCallback != NULL)||
                (pstcInternData->pfnArbitrationLostCallback != NULL)|| 
                (pstcInternData->pfnReservedAddressDetectedCallback != NULL)||
                (pstcInternData->pfnNACKCallback != NULL))
        {
            //Enable Interupt 
            pstcI2c->unIBCRS.stcField.u1INTES=1;
        }
                  
    }
    else if(bEnableRx == TRUE)//Check if Reception Interupt are requested  
    {
        //Enable Reception Interupt 
        pstcI2c->unSMRS.stcField.u1RIES=1;
    }
    else if(bEnableTx == TRUE) //Check if Transmission Interupt are requested  
    {
        //Enable Transmission Interupt
        pstcI2c->unSMRS.stcField.u1TIES=1;
    }
  
    return Ok;
    
}/* Mfs_I2c_EnableInterupt */

/**
 *****************************************************************************
 ** \brief Disable Interupt
 **
 ** This Function Disable interupts.
 **
 ** \param [in]  pstcI2c                   Pointer to I2C instance register area
 ** \param [in]  bDisableStatus            Status Interupt Disable requested
 ** \param [in]  bDisableRx                Reception Interupt disable requested     
 ** \param [in]  bDisableTx                Transmission Interupt disable requested 
 **
 ** \retval Ok                             Intrupt Enabled successfully
 ** \retval ErrorInvalidParameter If one of following conditions are met:
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL
 **
 *****************************************************************************/
en_result_t Mfs_I2c_DisableInterupt(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                                    boolean_t bDisableStatus,
                                    boolean_t bDisableRx, 
                                    boolean_t bDisableTx)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    if(bDisableStatus == TRUE)//Check if Status Interupt are requested 
    {
        //Disable Error/staus Interupts
        pstcI2c->unIBCRC.stcField.u1INTC=1;
      
        //disable Repeated start or stop condition interupt
        pstcI2c->unIBCRC.stcField.u1CNDEC=1;       
    }
    else if(bDisableRx == TRUE)//Check if Reception Interupt are requested  
    {
        //Disable Reception Interupt 
        pstcI2c->unSMRC.stcField.u1RIEC=1;
    }
    else if(bDisableTx == TRUE) //Check if Transmission Interupt are requested  
    {
        //Disable Transmission Interupt
        pstcI2c->unSMRC.stcField.u1TIEC=1;
    }
     
    return Ok;

}/* Mfs_I2c_DisableInterupt */

/**
 *****************************************************************************
 ** \brief Enable Transmission FIFO
 **
 ** This Function Enables Transmission FIFO Operation for I2c
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                        Pointer to I2C instance register area
 ** \param [in]  bFifoTxInterruptEnable         Enable fifo interupt or not
 **
 **  
 ** \retval Ok                          FIFO for Transmission enabled successfully.
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **
 *****************************************************************************/
en_result_t Mfs_I2c_EnableTxFifo(volatile  stc_cpg_mfsn_i2c_t *pstcI2c,
                                 boolean_t bFifoTxInterruptEnable)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    //Transmission FIFO: FIFO1; reception FIFO: FIFO2 
    pstcI2c->unFCR1.stcField.u1FSEL=0;
  
    //Enable FIFO1 operation. 
    pstcI2c->unFCR0S.stcField.u1FE1S=1;
  
    //Enable FIFO2 operation  
    pstcI2c->unFCR0S.stcField.u1FE2S=1;
  
    //Reset FIFO1 
    pstcI2c->unFCR0.stcField.u1FCL1=1;
  
    //Reset FIFO2 
    pstcI2c->unFCR0.stcField.u1FCL2=1;
  
    // FIFO transmission interrupt enable/disable
    pstcI2c->unFCR1.stcField.u1FTIE=(bFifoTxInterruptEnable==TRUE)?1:0;
    
    return Ok;

} /* Mfs_I2c_EnableTxFifo */


/**
 *****************************************************************************
 ** \brief Disable Transmission/Reception FIFO
 **
 ** This Function Disables Transmission and Reception FIFO Operation for I2c
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                        Pointer to I2C instance register area
 **
 ** \retval Ok                          FIFO for Transmission/Reception disabled successfully.
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **  
 *****************************************************************************/
en_result_t Mfs_I2c_DisableRxTxFifo(volatile stc_cpg_mfsn_i2c_t *pstcI2c)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    //Transmission FIFO: FIFO1; reception FIFO: FIFO2 
    pstcI2c->unFCR1.stcField.u1FSEL=0;
  
    //Disable FIFO1 operation. 
    pstcI2c->unFCR0C.stcField.u1FE1C=1;
  
    //Disable FIFO2 operation  
    pstcI2c->unFCR0C.stcField.u1FE2C=1;
  
    //Reset FIFO1 
    pstcI2c->unFCR0.stcField.u1FCL1=1;
  
    //Reset FIFO2 
    pstcI2c->unFCR0.stcField.u1FCL2=1;
  
    // FIFO transmission interrupt disable
    pstcI2c->unFCR1C.stcField.u1FTIEC=1;
  
    return Ok;

} /* Mfs_I2c_DisableRxTxFifo */


/**
 *****************************************************************************
 ** \brief Mfs_I2c_fifoEnableRx
 **
 ** This Function Enable FIFO Operation for I2c
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in]  pstcI2c                        Pointer to I2C instance register area
 ** \param [in]  bFifoRxInterruptEnable         Enable fifo interupt or not
 ** \param [in]  u32Readbytecount               Number of bytes to be read
 **
 ***
 ** \retval Ok                          FIFO for Reception enabled successfully.
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **  
 *****************************************************************************/
en_result_t Mfs_I2c_EnableRxFifo(volatile stc_cpg_mfsn_i2c_t *pstcI2c,
                                 boolean_t bFifoRxInterruptEnable,
                                 uint32_t  u32Readbytecount)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    //Assign bytes to be read to static variable
    m_u32ReadBytes=u32Readbytecount; 
  
    //Transmission FIFO: FIFO1; reception FIFO: FIFO2 
    pstcI2c->unFCR1.stcField.u1FSEL=0;
  
    //Enable FIFO1 operation. 
    pstcI2c->unFCR0S.stcField.u1FE1S=1;
  
    //Enable FIFO2 operation  
    pstcI2c->unFCR0S.stcField.u1FE2S=1;
  
    //Reset FIFO1 
    pstcI2c->unFCR0.stcField.u1FCL1=1;
  
    //Reset FIFO2 
    pstcI2c->unFCR0.stcField.u1FCL2=1;
  
    //Set number of bytes to be received
    // pstcI2c->unFBYTE.stcField.u8FBYTE1=readbytecount;
    pstcI2c->unFBYTE.stcField.u8FBYTE2=u32Readbytecount;

    // FIFO Reception interrupt enable
    pstcI2c->unSMRS.stcField.u1RIES=bFifoRxInterruptEnable;
  
    // FIFO transmission interrupt disable
    pstcI2c->unSMRC.stcField.u1TIEC=1;
  
    //No transmission FIFO data request 
    pstcI2c->unFCR1C.stcField.u1FDRQC=1;
  
    return Ok;
    
} /* Mfs_I2c_EnableRxFifo */


/**
 *****************************************************************************
 ** \brief Write String using Transmission FIFO Operation
 **
 ** This Function writes a provided string to the i2c bus usinf Transmission fifo.
 ** This Function must be called after initialisation, Enabling FIFO, start, and 
 ** write address already written on i2c bus.
 **
 ** \pre Mfs_I2c_Init() and Mfs_I2c_Start() must be called
 **
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 ** \param [in]   cString               Sting value that is to be written on i2c bus
 **
 ** \retval Ok                          String written to i2c bus successfully
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **          
 *****************************************************************************/
en_result_t Mfs_I2c_WriteString(volatile stc_cpg_mfsn_i2c_t *pstcI2c, 
                                const char *cString)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // Write the datd to be transmitted to FIFO buffer
    for (u32count=0; u32count<strlen(cString); u32count++)    
    {
        // load data or address in to register
        pstcI2c->unRDR.u8Register = cString[u32count];                  
    }
    
    // clear transfer end intrerupt flag
    pstcI2c->unIBCRC.stcField.u1INTC = 1;
    
    // look if transfer is in process
    while (0 ==  pstcI2c->unIBCR.stcField.u1INT)          
    {
        PDL_WAIT_LOOP_HOOK();
    }  

    // wait for number of Acknowledges
    for (u32count=0; u32count<strlen(cString); u32count++)
    {
        Mfs_I2c_Acknowlegde(pstcI2c);  
    }

    return Ok;

} /* Mfs_I2c_WriteString */


/**
 *****************************************************************************
 ** \brief Read String using Reception FIFO
 **
 ** This Function receives data and stores them in a static array from reception
 ** FIFO Buffer on the i2c bus. This Function must be called after Enabling FIFO,
 ** start, and read address already written on i2c bus.
 **
 ** \pre  Mfs_I2c_Init() and Mfs_I2c_Start() must be called
 ** \pre  Mfs_Fifo_EnableRx() must be called.
 ** \post Mfs_I2c_GetReadValues() can be called to get values back
 **
 ** \param [in]  pstcI2c                Pointer to I2C instance register area
 **
 ** \retval Ok                          Sequence Read successfully
 ** \retval ErrorInvalidParameter If 
 **         - pstcI2c == NULL
 **         - pstcInternData == NULL
 **          
 *****************************************************************************/
en_result_t Mfs_I2c_ReadString(volatile stc_cpg_mfsn_i2c_t *pstcI2c)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
    
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData ; 
  
    // Get pointer to internal data ...
    pstcInternData = I2cGetInternDataPtr( pstcI2c ) ;
  
    //check for NULL pointer */
    if ( pstcInternData == NULL )
    {
        // The pstcRlt that was passed is not available or not enabled */
        return ErrorInvalidParameter ;
    }
    
    // Acknowledge has to send
    pstcI2c->unIBCRS.stcField.u1ACKES = 1;
    // Write Address and dummy data as much as we want to read
    pstcI2c->unRDR.u8Register= pstcInternData->u8SlaveAddress | I2C_READ;
    for (u32count=0; u32count<m_u32ReadBytes; u32count++)    
    {
        // load data or address in to register
        pstcI2c->unRDR.u8Register = 0;                  
    }
    
    // restart (= continue)
    pstcI2c->unIBCRS.stcField.u1ACTS=1;
    
    //check if interupt is not enabled because clearance of interupt requires reading of fifo
    if( pstcI2c->unSMR.stcField.u1RIE==0)
    {
        //wait for full reception
        while (0 == pstcI2c->unSSR.stcField.u1RDRF)          
        {
            PDL_WAIT_LOOP_HOOK();
        }
        
        //Read Reception FIFO Buffer
        for (u32count=0; u32count< m_u32ReadBytes; u32count++)
        { 
            m_32ReadValuesFifo[u32count]=pstcI2c->unRDR.u8Register;
           /* //Save into internal read buffer
            pstcInternData->m_readBuffer[count]=pstcI2c->unRDR.u8Register;*/
        }
    }
    else //do nothing and wait for interupt
    {
        while (0 ==  pstcI2c->unIBCR.stcField.u1INT)          
        {
            PDL_WAIT_LOOP_HOOK();
        }
    }
    
    return Ok;
  
}/* Mfs_I2c_ReadString */


/**
 *****************************************************************************
 ** \brief De-Initializes the I2C
 **
 ** This Function Releases all resources of I2C instance and reset all i2c 
 ** registers to default values.
 **
 ** \pre Mfs_I2c_Init() must be called
 **
 ** \param [in] pstcI2c               Pointer to I2C instance register area
 **                                  
 ** \retval Ok                        Deinitialized successfully
 ** \retval ErrorInvalidParameter If one of the following conditions are met:
 **          - pstcI2c == NULL
 **          - pstcInternData == NULL(invalid or disabled I2C unit )
 **               
 *****************************************************************************/
en_result_t Mfs_I2c_DeInit(volatile stc_cpg_mfsn_i2c_t *pstcI2c)
{
    // Check for NULL-Pointer
    if (pstcI2c == NULL)
    {
        return ErrorInvalidParameter;
    }
  
    // Pointer to the internal data structure
    stc_i2c_intern_data_t* pstcInternData; 
  
    // Get pointer to internal data 
    pstcInternData = I2cGetInternDataPtr( pstcI2c );
  
    // check for NULL pointer 
    if (pstcInternData == NULL)
    {
        // The pstcI2C that was passed is not available or not enabled 
        return ErrorInvalidParameter;
    }

    // Reset internal data for the instance
    // Clear the callback ISRs
    pstcInternData->pfnRepeatedStartCallback              =    NULL;          
    pstcInternData->pfnStopConditionCallback              =    NULL;
    pstcInternData->pfnBusErrorCallback                   =    NULL;
    pstcInternData->pfnArbitrationLostCallback            =    NULL;
    pstcInternData->pfnReservedAddressDetectedCallback    =    NULL;
    pstcInternData->pfnNACKCallback                       =    NULL;
    pstcInternData->pfnTransmissionFifoOverRunCallback    =    NULL;
    pstcInternData->pfnReceptionFifoUnderRunCallback      =    NULL;
    pstcInternData->pfnReceptionFifoFullCallback          =    NULL;
    
    // Clear and disable Interupts and reset the registers
    // Now Reset HW registers
    // Bus control register, Serial mode register, Serial status register, bus status register
    // Serial Auxiliary Control Status register, FIFO Control Clear Register 0 & 1 and Extended Status Clear register
    pstcI2c->unIBCRC.u8Register    =    0xFF;
    pstcI2c->unSMRC.u8Register     =    0xFF;
    pstcI2c->unSSRC.u8Register     =    0xFF;
    pstcI2c->unIBSRC.u8Register    =    0xFF;
    pstcI2c->unSACSRC.u16Register  =    0xFFFF;
    pstcI2c->unFCR1C.u8Register    =    0xFF;
    pstcI2c->unFCR0C.u8Register    =    0xFF;
    pstcI2c->unESRC.u8Register     =    0xFF;

    return Ok;
    
} /* Mfs_I2c_DeInit */

/** @} */
#endif /* (PDL_PERIPHERAL_I2C_ACTIVE) */

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/


