/*!
* @file     Fls.c
*
* @version  1.0.0
*
* @brief    Code file of AUTOSAR FLS driver
*
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_01-Otc-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

/*
* MISRA-C:2012 compliance checks
*
*      Fls_c_MISRA_REF1
*          Breaks the required M3CM Rule-18.4 of MISRA 2012 guidelines,
*          The +, -, += and -= operators should not be applied to an expression of pointer type.
*
*      Fls_c_MISRA_REF2
*          Breaks the required M3CM Rule-11.5 of MISRA 2012 guidelines,
*          A conversion should not be performed from pointer to void into pointer to object.
*/

#ifdef __cplusplus
    extern "C"{
#endif

    #include "Fls_Fmc.h"

#if((STD_ON == FLS_DETECT_DEV_ERROR_EN) || (STD_ON == FLS_DETECT_RUNTIME_ERROR_EN) || \
    (STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN))
    #include "Det.h"
#endif

#include "Fls_Signature.h"
#include "SchM_Fls.h"

#if defined(__ICCARM__)
#include "intrinsics.h"
#endif

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup FLS_Driver
  * @brief FLS driver modules
  @{
*/

/** @defgroup FLS_Macros
  @{
*/
/**************************************************************************
                  VENDOR ID & AUTOSAR VERSION INFO
**************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define FLS_VENDOR_ID                        0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_AR_RELEASE_MAJOR_VERSION         0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_AR_RELEASE_MINOR_VERSION         0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_AR_RELEASE_REVISION_VERSION      0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_SW_MAJOR_VERSION                 0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_SW_MINOR_VERSION                 0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_SW_PATCH_VERSION                 0x00U

/**@} end of group FLS_Macros */

/**************************************************************************
                    VERSION INFOMATION VERIFICATION
**************************************************************************/
/* Make sure the vendor id is the same between Fls.c and Fls_Fmc.h */
#if (FLS_VENDOR_ID != FLS_FLASH_H_VENDOR_ID)
    #error "Vendor id mismatch between Fls.c and Fls_Fmc.h"
/* Make sure the AUTOSAR major version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_AR_RELEASE_MAJOR_VERSION != FLS_FLASH_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR Major Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_AR_RELEASE_MINOR_VERSION != FLS_FLASH_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR Minor Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_AR_RELEASE_REVISION_VERSION != FLS_FLASH_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
/* Make sure the software major version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_SW_MAJOR_VERSION != FLS_FLASH_H_SW_MAJOR_VERSION)
    #error "Software Major Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
/* Make sure the software minor version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_SW_MINOR_VERSION != FLS_FLASH_H_SW_MINOR_VERSION)
    #error "Software Minor Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
/* Make sure the software patch version number is the same between Fls.c and Fls_Fmc.h */
#if (FLS_SW_PATCH_VERSION != FLS_FLASH_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Fls.c and Fls_Fmc.h"
#endif
#endif

#if(( STD_ON == FLS_DETECT_DEV_ERROR_EN ) || ( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN ) || \
    ( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN ))
#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    #if (STD_ON == PWM_DEV_ERROR_DETECT)
        /* Make sure the AUTOSAR major version number is the same between Fls.c and Det.h */
        #if (FLS_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION)
            #error "AUTOSAR Major Version Number mismatch between Fls.c and Det.h "
        #endif
        /* Make sure the AUTOSAR minor version number is the same between Fls.c and Det.h */
        #if (FLS_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR Minor Version Number mismatch between Fls.c and Det.h "
        #endif
    #endif
#endif
#endif

/* Make sure the vendor id is the same between Fls.c and Fls_Signature.h */
#if (FLS_VENDOR_ID != FLS_SIGNATURE_H_VENDOR_ID)
    #error "Vendor id mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_AR_RELEASE_MAJOR_VERSION != FLS_SIGNATURE_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR Major Version Number mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_AR_RELEASE_MINOR_VERSION != FLS_SIGNATURE_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR Minor Version Number mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_AR_RELEASE_REVISION_VERSION != FLS_SIGNATURE_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the software major version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_SW_MAJOR_VERSION != FLS_SIGNATURE_H_SW_MAJOR_VERSION)
    #error "Software Major Version Number mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the software minor version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_SW_MINOR_VERSION != FLS_SIGNATURE_H_SW_MINOR_VERSION)
    #error "Software Minor Version Number mismatch between Fls.c and Fls_Signature.h"
#endif
/* Make sure the software patch version number is the same between Fls.c and Fls_Signature.h */
#if (FLS_SW_PATCH_VERSION != FLS_SIGNATURE_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Fls.c and Fls_Signature.h"
#endif

#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    /* Make sure the AUTOSAR major version number is the same between Fls.c and SchM_Fls.h */
    #if (FLS_AR_RELEASE_MAJOR_VERSION != SCHM_FLS_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR Major Version Number mismatch between Fls.c and SchM_Fls.h "
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Fls.c and SchM_Fls.h */
    #if (FLS_AR_RELEASE_MINOR_VERSION != SCHM_FLS_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Fls.c and SchM_Fls.h "
    #endif
#endif

/**************************************************************************
                    LOCAL CONSTANT DEFINITION
**************************************************************************/

#define FLS_START_SEC_CONST_32
#include "Fls_MemMap.h"

#ifdef G32A_C_DS6

    /** @defgroup FLS_Variable
      @{
    */

    extern CONST(uint32, FLS_CONST) Load$$ER_flash_rsvd_fls_region$$Base; /** Write access code entry */
    extern CONST(uint32, FLS_CONST) Image$$ER_flash_rsvd_fls_region$$Length;  /** Write access code size */

    /**@} end of group FLS_Variable */

    /** @defgroup FLS_Macros
      @{
    */

    #define Fls_ACWriteRomStart    (&Load$$ER_flash_rsvd_fls_region$$Base)    /** Write access code entry */
    #define Fls_ACWriteSize        (((uint32)(&Image$$ER_flash_rsvd_fls_region$$Length)+3U)/4U)  /** Write access code size */

    #define Fls_ACEraseRomStart    (&Load$$ER_flash_rsvd_fls_region$$Base)  /** Erase access code entry */
    #define Fls_ACEraseSize        (((uint32)(&Image$$ER_flash_rsvd_fls_region$$Length)+3U)/4U)  /** Erase access code size */

    /**@} end of group FLS_Macros */

    /** @defgroup FLS_Fuctions
      @{
    */

    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACWriteRomStart(void)
    {
        return Fls_ACWriteRomStart;
    }

    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACEraseRomStart(void)
    {
        return Fls_ACEraseRomStart;
    }

    /**@} end of group FLS_Fuctions */

#elif defined(G32A_C_CODEWARRIOR)

    /** @defgroup FLS_Macros
      @{
    */

    #define Fls_ACWriteRomStart    (__SEG_START_acfls_code_rom)    /** Write access code entry */
    #define Fls_ACWriteSize        (((uint32)(__SEG_SIZE_acfls_code_rom)+3U)/4U)  /** Write access code size */

    /**@} end of group FLS_Macros */

    /** @defgroup FLS_Variable
      @{
    */

    extern CONST(uint32, FLS_CONST) __SEG_START_acfls_code_rom[1]; /** Write access code entry */
    extern CONST(uint32, FLS_CONST) __SEG_SIZE_acfls_code_rom[1];  /** Write access code size */

    /**@} end of group FLS_Variable */

    /** @defgroup FLS_Macros
      @{
    */

    #define Fls_ACEraseRomStart    (__SEG_START_acfls_code_rom)  /** Erase access code entry */
    #define Fls_ACEraseSize        (((uint32)(__SEG_SIZE_acfls_code_rom)+3U)/4U)  /** Erase access code size */

    /**@} end of group FLS_Macros */

    /** @defgroup FLS_Variable
      @{
    */

    extern CONST(uint32, FLS_CONST) __SEG_START_acfls_code_rom[1]; /** Erase access code entry */
    extern CONST(uint32, FLS_CONST) __SEG_SIZE_acfls_code_rom[1];  /** Erase access code size */

    /**@} end of group FLS_Variable */

#elif defined(G32A_C_IAR)

/* IAR: __section_begin/__section_end require a matching #pragma section (Pa053). */
#pragma section = ".acfls_code_rom"

    /** @defgroup FLS_Macros
      @{
    */

    #define Fls_ACWriteRomStart    ((const uint32 *)__section_begin(".acfls_code_rom"))    /** Write access code entry */
    #define Fls_ACWriteSize        ((((uint32)((const uint8 *)__section_end(".acfls_code_rom") - (const uint8 *)__section_begin(".acfls_code_rom"))) + 3U) / 4U)  /** Write access code size */

    #define Fls_ACEraseRomStart    ((const uint32 *)__section_begin(".acfls_code_rom"))  /** Erase access code entry */
    #define Fls_ACEraseSize        ((((uint32)((const uint8 *)__section_end(".acfls_code_rom") - (const uint8 *)__section_begin(".acfls_code_rom"))) + 3U) / 4U)  /** Erase access code size */

    /**@} end of group FLS_Macros */

    /** @defgroup FLS_Fuctions
      @{
    */
    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACWriteRomStart(void)
    {
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        return (const uint32 *)__section_begin(".acfls_code_rom");
    }

    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACEraseRomStart(void)
    {
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        return (const uint32 *)__section_begin(".acfls_code_rom");
    }

    /**@} end of group FLS_Fuctions */

#else

    /** @defgroup FLS_Variable
      @{
    */
    extern CONST(uint32, FLS_CONST) Fls_ACWriteRomStart[1]; /** Write access code entry */
    extern CONST(uint32, FLS_CONST) Fls_ACWriteSize[1];     /** Write access code size */

    extern CONST(uint32, FLS_CONST) Fls_ACEraseRomStart[1]; /** Erase access code entry */
    extern CONST(uint32, FLS_CONST) Fls_ACEraseSize[1];     /** Erase access code size */

    /**@} end of group FLS_Variable */

    /** @defgroup FLS_Fuctions
      @{
    */

    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACWriteRomStart(void)
    {
        return Fls_ACWriteRomStart;
    }

    static FUNC( const uint32 *, FLS_CODE ) Fls_GetACEraseRomStart(void)
    {
        return Fls_ACEraseRomStart;
    }

    /**@} end of group FLS_Fuctions */

#endif

#define FLS_STOP_SEC_CONST_32
#include "Fls_MemMap.h"

/**************************************************************************
                    GLOBAL VARIABLE
**************************************************************************/
#define FLS_START_SEC_VAR_INIT_32
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_32
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

/** Current job operation type: read, write, compare, erase */
static VAR(Fls_JobOpnType, FLS_VAR) s_jobOpnType = JOB_TO_ERASE;
/** Pointer to flash configuration */
P2CONST(Fls_ConfigType, FLS_VAR, FLS_APPL_CONST) g_flsConfigPtr = NULL_PTR;
/** Last flash job result */
VAR(volatile MemIf_JobResultType, FLS_VAR) g_jobResult = MEMIF_JOB_OK;

/** Start sector ID to be erased */
VAR(Fls_SectorIdxType, FLS_VAR) g_EraseSectorStartId = 0UL;
/** End sector ID to be erased */
VAR(Fls_SectorIdxType, FLS_VAR) g_EraseSectorEndId = 0UL;

/** Start address to be writted */
static VAR(Fls_AddressType, FLS_VAR) g_WriteStartAddr = 0UL;
/** End address to be writted */
static VAR(Fls_AddressType, FLS_VAR) g_WriteEndAddr = 0UL;
/** Current sector ID to be writted */
VAR(Fls_SectorIdxType, FLS_VAR) g_WriteCurSectorId = 0UL;

/** Start address to be read */
static VAR(Fls_AddressType, FLS_VAR) g_ReadStartAddr = 0UL;
/** End address to be read */
static VAR(Fls_AddressType, FLS_VAR) g_ReadEndAddr = 0UL;
/** Current sector ID to be read */
VAR(Fls_SectorIdxType, FLS_VAR) g_ReadCurSectorId = 0UL;

#if( STD_ON == FLS_COMPARE_API_EN )
/** Start address to be compared */
static VAR(Fls_AddressType, FLS_VAR) g_CompareStartAddr = 0UL;
/** End address to be compared */
static VAR(Fls_AddressType, FLS_VAR) g_CompareEndAddr = 0UL;
/** Current sector ID to be compared */
VAR(Fls_SectorIdxType, FLS_VAR) g_CompareCurSectorId = 0UL;
#endif

#if( STD_ON == FLS_BLANKCHECK_API_EN )
/** Start address to be blank checked */
static VAR(Fls_AddressType, FLS_VAR) g_BlankCheckStartAddr = 0UL;
/** End address to be blank checked */
static VAR(Fls_AddressType, FLS_VAR) g_BlankCheckEndAddr = 0UL;
/** Current sector ID to be blank checked */
VAR(Fls_SectorIdxType, FLS_VAR) g_BlankCheckCurSectorId = 0UL;
#endif

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

/**************************************************************************
                    LOCAL MACRO DEFINITION
**************************************************************************/
/** @defgroup FLS_Macros
  @{
*/

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    /** Get current flash total size(bytes) */
    #define FLS_CFG_TOTAL_SIZE  ((*(g_flsConfigPtr->sectorEndAddrPtr))[g_flsConfigPtr->sectorCnt - 1U] + 1U)
#endif

/** Unload (erase) write or erase access code from RAM */
#define FLS_UNLOAD_PATTERN_VAL  0xFFFFFFFFU

/**@} end of group FLS_Macros */

/**************************************************************************
                    LOCAL VARIABLE
**************************************************************************/
#define FLS_START_SEC_VAR_INIT_8
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

/** Record the new job accepted status */
static VAR(uint8, FLS_VAR) s_jobStart = 0U;
/** Pointer to destination data buffer, used only by read job */
static P2VAR(uint8, FLS_VAR, FLS_APPL_DATA) s_jobDataDestPtr = NULL_PTR;
/** Pointer to source data buffer */
static P2CONST(uint8, FLS_VAR, FLS_APPL_CONST) s_jobDataSrcPtr = NULL_PTR;

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_8
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

/** last job result  */
static VAR(MemIf_JobResultType, FLS_VAR) s_jobResult = MEMIF_JOB_OK;
/** The one cycle max bytes number of write in Fls_MainFunction */
static VAR(Fls_LengthType, FLS_VAR) s_maxWrite = 0UL;
/** The one cycle max bytes number of read or compare in Fls_MainFunction */
static VAR(Fls_LengthType, FLS_VAR) s_maxRead = 0UL;

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

/**************************************************************************
                    LOCAL FUNCTION DECLARATION
**************************************************************************/
#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

/** @defgroup FLS_Fuctions
  @{
*/

static FUNC(void, FLS_CODE) Fls_ACLoad  (CONST(Fls_JobOpnType, AUTOMATIC) JobOpnType);
static FUNC(void, FLS_CODE) Fls_ACUnload(CONST(Fls_JobOpnType, AUTOMATIC) JobOpnType);

static FUNC(Fls_SectorIdxType, FLS_CODE) Fls_GetSectorIdxByAddr(CONST(Fls_AddressType, AUTOMATIC) TargetAddr);

static FUNC(MemIf_JobResultType, FLS_CODE) Fls_StartJobErase(void);

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckInitializeOrNot( CONST(uint8, AUTOMATIC) ApiId );

static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckStartAddrAlign( CONST(Fls_AddressType, AUTOMATIC) TargetAddr,
                                                                 CONST(uint8, AUTOMATIC) ApiId );

static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckEndAddrAlign( CONST(Fls_AddressType, AUTOMATIC) TargetAddr,
                                                               CONST(Fls_LengthType, AUTOMATIC) Length,
                                                               CONST(uint8, AUTOMATIC) ApiId );

static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferPtr( P2CONST(uint8,AUTOMATIC,FLS_APPL_CONST) pBufferPtr,
                                                            CONST(uint8, AUTOMATIC) ApiId );

static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferScope( CONST(Fls_AddressType, AUTOMATIC) Buffer,
                                                              CONST(uint8, AUTOMATIC) ApiId );

static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferAndLengthScope( CONST(Fls_AddressType, AUTOMATIC) Buffer,
                                                                       CONST(Fls_LengthType, AUTOMATIC) Length,
                                                                       CONST(uint8, AUTOMATIC) ApiId );
#endif

static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataWrite(void);

static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataRead(void);

#if( STD_ON == FLS_COMPARE_API_EN )
static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataCompare(void);
#endif

#if (STD_ON == FLS_BLANKCHECK_API_EN)
static FUNC(MemIf_JobResultType, FLS_CODE) Fls_StartJobDataBlankCheck(void);
#endif

/**@} end of group FLS_Fuctions */

#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"

/**************************************************************************
                    LOCAL FUNCTION
**************************************************************************/
#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

/** @defgroup FLS_Fuctions
  @{
*/

/*!
* @brief            Service for unload erase or write access code to RAM which Fills with FLS_UNLOAD_PATTERN_VAL
*
* @param[in]        JobOpnType    Access code load type : JOB_TO_ERASE / JOB_TO_WRITE
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*
* @note    Non-AUTOSAR support function
*/
static FUNC( void, FLS_CODE ) Fls_ACUnload( CONST( Fls_JobOpnType, AUTOMATIC) JobOpnType )
{
    VAR( uint32, AUTOMATIC) numElements = 0U;
    VAR( uint32, AUTOMATIC) count = 0U;
    P2VAR( uint32, AUTOMATIC, FLS_APPL_DATA ) cfgRamPtr = NULL_PTR;

    if(JOB_TO_ERASE == JobOpnType)
    {
        cfgRamPtr = (uint32*)(g_flsConfigPtr->acErasePtr);
        /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        numElements = (uint32)(Fls_ACEraseSize);
    }
    else if(JOB_TO_WRITE == JobOpnType)
    {
        cfgRamPtr = (uint32*)(g_flsConfigPtr->acWritePtr);
        /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        numElements = (uint32)(Fls_ACWriteSize);
    }
    else
    {
        /* do nothing */
    }

    for (count = 0U; count < numElements; count++)
    {
        cfgRamPtr[count] = FLS_UNLOAD_PATTERN_VAL;
    }
}

/*!
* @brief            Service for Load erase or write access code to RAM
*
* @param[in]        JobOpnType    Access code load type : JOB_TO_ERASE / JOB_TO_WRITE
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*
* @note    Non-AUTOSAR support function
*/
static FUNC( void, FLS_CODE ) Fls_ACLoad( CONST( Fls_JobOpnType, AUTOMATIC) JobOpnType )
{
    VAR( uint32, AUTOMATIC) numElements = 0U;
    VAR( uint32, AUTOMATIC) count = 0U;
    P2VAR( uint32, AUTOMATIC, FLS_APPL_DATA ) cfgRamPtr = NULL_PTR;
    P2CONST( uint32, AUTOMATIC, FLS_APPL_CONST ) cfgRomPtr = NULL_PTR;

    if(JOB_TO_ERASE == JobOpnType)
    {
        cfgRomPtr = Fls_GetACEraseRomStart();
        /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        numElements = (uint32)(Fls_ACEraseSize);
        cfgRamPtr = (uint32*)(g_flsConfigPtr->acErasePtr);
    }
    else if(JOB_TO_WRITE == JobOpnType)
    {
        cfgRomPtr = Fls_GetACWriteRomStart();
        /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
        /*** @warning Fls_c_MISRA_REF2 [I] Cast from a pointer to void to a pointer to object type. */
        numElements = (uint32)(Fls_ACWriteSize);
        cfgRamPtr = (uint32*)(g_flsConfigPtr->acWritePtr);
    }
    else
    {
        /* do nothing */
    }

#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
    /* for gcc platform */
    for (count = 0U; count < numElements + 1; count++)
    {
        cfgRamPtr[count] = cfgRomPtr[count];
    }
#else
    for (count = 0U; count < numElements; count++)
    {
        cfgRamPtr[count] = cfgRomPtr[count];
    }
#endif
}

/*!
* @brief            Calculate the sector index according to Target Address
*
* @param[in]        TargetAddr    Target address
* @param[out]       None
* @param[in,out]    None
*
* @retval  sectorIdx : range 0 .. (Fls_pConfigPtr->sectorCnt - 1)
*
* @note    Non-AUTOSAR support function
*/
static FUNC(Fls_SectorIdxType, FLS_CODE) Fls_GetSectorIdxByAddr( CONST(Fls_AddressType, AUTOMATIC) TargetAddr )
{
    VAR( Fls_SectorIdxType, AUTOMATIC ) sectorIdx = 0UL;

    for(sectorIdx = 0UL; sectorIdx < g_flsConfigPtr->sectorCnt; sectorIdx++)
    {
        if( TargetAddr <= (*(g_flsConfigPtr->sectorEndAddrPtr))[sectorIdx] )
        {
            break;  /* TargetAddr belongs to this sector, calculate complete */
        }
        else
        {
            /* do nothing */
        }
    }

    return sectorIdx;
}

/*!
* @brief            Execute to erase flash sector
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_OK, MEMIF_JOB_FAILED
*
* @note    Non-AUTOSAR support function
*/
static FUNC( MemIf_JobResultType, FLS_CODE )  Fls_StartJobErase( void )
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_PENDING;
    VAR( Fls_LLDResultType, AUTOMATIC ) lldRetSts = FLS_E_OK;

    lldRetSts = Fls_FMC_Erase();

    if( FLS_E_OK == lldRetSts )
    {
        retvalue = MEMIF_JOB_OK;
    }
    else
    {
        #if( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN )
        (void)Det_ReportTransientFault((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                               FLS_MAINFUNCTION_SVC_ID, FLS_E_ERASE_FAILED);
        #endif
        retvalue = MEMIF_JOB_FAILED;
    }

    return retvalue;
}

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
/*!
* @brief            Check whether the module has been initialized
*
* @param[in]        ApiId    API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckInitializeOrNot( CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    if( NULL_PTR == g_flsConfigPtr )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_UNINIT);
        retValue = E_NOT_OK;
    }
    else
    {
        /* do nothing */
    }

    return retValue;
}

/*!
* @brief            Check whether the starting address is valid and aligned
*
* @param[in]        TargetAddr    starting address
* @param[in]        ApiId         API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckStartAddrAlign( CONST(Fls_AddressType, AUTOMATIC) TargetAddr,
                                                                 CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    VAR( uint16, AUTOMATIC ) standard = (FLS_ERASE_SVC_ID == ApiId) ? PAGE_SIZE : 8U;

    if((TargetAddr < FLS_CFG_TOTAL_SIZE) && (0U == (TargetAddr % standard)))
    {
        /* do nothing */
    }
    else
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_PARAM_ADDRESS);
        retValue = E_NOT_OK;
    }

    return retValue;
}

/*!
* @brief            Check whether the end address is valid and aligned
*
* @param[in]        TargetAddr    end address
* @param[in]        Length        data length
* @param[in]        ApiId         API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckEndAddrAlign( CONST(Fls_AddressType, AUTOMATIC) TargetAddr,
                                                               CONST(Fls_LengthType, AUTOMATIC) Length,
                                                               CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    VAR( uint16, AUTOMATIC ) standard = (FLS_ERASE_SVC_ID == ApiId) ? PAGE_SIZE : 8U;

    if(((TargetAddr + Length - 1U) < FLS_CFG_TOTAL_SIZE) && (0U == (Length % standard)))
    {
        /* do nothing */
    }
    else
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_PARAM_LENGTH);
        retValue = E_NOT_OK;
    }

    return retValue;
}

/*!
* @brief            Check whether the pointer to the data buffer is NILL
*
* @param[in]        pBufferPtr    Pointer to the data buffer
* @param[in]        ApiId         API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferPtr( P2CONST(uint8, AUTOMATIC, FLS_APPL_CONST) pBufferPtr,
                                                              CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    if(NULL_PTR == pBufferPtr)
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_PARAM_DATA);
        retValue = E_NOT_OK;
    }
    else
    {
        /* do nothing */
    }

    return retValue;
}

/*!
* @brief            Check whether the starting address is valid
*
* @param[in]        Buffer    starting address
* @param[in]        ApiId     API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferScope( CONST(Fls_AddressType, AUTOMATIC) Buffer,
                                                              CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    if(Buffer >= FLS_CFG_TOTAL_SIZE)
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_PARAM_ADDRESS);
        retValue = E_NOT_OK;
    }
    else
    {
        /* do nothing */
    }

    return retValue;
}

/*!
* @brief            Check whether the data length is valid
*
* @param[in]        Buffer    starting address
* @param[in]        Length    data length
* @param[in]        ApiId     API ID to be tested
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK, E_NOT_OK
*
* @note    Non-AUTOSAR support function
*/
static FUNC( Std_ReturnType, FLS_CODE ) Fls_CheckBufferAndLengthScope( CONST(Fls_AddressType, AUTOMATIC) Buffer,
                                                                       CONST(Fls_LengthType, AUTOMATIC) Length,
                                                                       CONST(uint8, AUTOMATIC) ApiId )
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

    if(( 0U == Length ) || ((Buffer + Length) > FLS_CFG_TOTAL_SIZE ))
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, ApiId, FLS_E_PARAM_LENGTH);
        retValue = E_NOT_OK;
    }
    else
    {
        /* do nothing */
    }

    return retValue;
}

/*!
* @brief            Check whether the write operation crosses a 256-byte half-page boundary
*
* @param[in]        TargetAddress    start address
* @param[in]        Length           data length
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK: The write range does not cross a half-page boundary (allowed)
*          E_NOT_OK: The write range crosses a half-page boundary (not allowed)
*
* @note    Non-AUTOSAR support function
*/
Std_ReturnType Fls_CheckCrossHalfPage(VAR(Fls_AddressType, AUTOMATIC) TargetAddress, VAR(Fls_LengthType,  AUTOMATIC) Length)
{
    Std_ReturnType ret = E_OK;

    /* The nearest following 256-multiple address (strictly greater than TargetAddress) */
    Fls_AddressType boundary = (Fls_AddressType)0U;

    Fls_AddressType start = TargetAddress;
    Fls_AddressType end = TargetAddress + (Fls_AddressType)Length;

    /* Get the nearest following 256-multiple address relative to TargetAddress */
    boundary = (Fls_AddressType)(((start / 256U) + (Fls_AddressType)1U) * 256U);
    
    /* Check whether the write range contains this boundary */
    if (boundary < end)
    {
        /* Check whether the offset is an integer multiple of FLS_PROGRAMMING_LENGTH */
        if ((((uint32)(boundary - start)) % FLS_PROGRAMMING_LENGTH) != 0U)
        {
            ret = E_NOT_OK;
        }
        else
        {
            /* do nothing */
        }
    }
    else
    {
        /* do nothing */
    }

    return ret;
}

#endif

/*!
* @brief            Calculate the parameters of the write task and determine the execution result
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_OK, MEMIF_JOB_FAILED, MEMIF_JOB_PENDING
*
* @note    Non-AUTOSAR support function
*/
static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataWrite(void)
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_PENDING;
    VAR( Fls_LLDResultType, AUTOMATIC ) writeResult = FLS_E_FAILED;
    /* write end address */
    VAR( Fls_AddressType, AUTOMATIC ) maxWriteEndAddr = 0UL;
    /* byte offset compare to the start address of current write sector */
    VAR( Fls_AddressType, AUTOMATIC ) writeByteOffset = 0UL;
    /* The length of the data written this time */
    /* If cross-sector writing is required, writeLength is not equal to s_maxWrite */
    VAR( Fls_AddressType, AUTOMATIC ) writeLength = 0U;
    
    if( g_WriteStartAddr > g_WriteEndAddr ) /* write complete */
    {
        retvalue = MEMIF_JOB_OK;
    }
    else
    {
        maxWriteEndAddr = (g_WriteEndAddr >= (g_WriteStartAddr + s_maxWrite)) ?
                                             (g_WriteStartAddr + s_maxWrite - 1U) : g_WriteEndAddr;
        do
        {
            writeByteOffset = g_WriteStartAddr - (*(g_flsConfigPtr->sectorBeginAddrPtr))[g_WriteCurSectorId];

            if((*(g_flsConfigPtr->sectorEndAddrPtr))[g_WriteCurSectorId] > maxWriteEndAddr)
            {
                writeLength = maxWriteEndAddr - g_WriteStartAddr + 1U;
            }
            else
            {
                writeLength = (*(g_flsConfigPtr->sectorEndAddrPtr))[g_WriteCurSectorId] - g_WriteStartAddr + 1U;
            }

            /* renew start address to writte */
            g_WriteStartAddr += writeLength;

            writeResult = Fls_FMC_Write( writeByteOffset, writeLength, s_jobDataSrcPtr );

            /* renew start address of the source data */
            /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
            s_jobDataSrcPtr += writeLength;
#if( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN )
            if(writeResult == FLS_E_FAILED)
            {
                (void)Det_ReportTransientFault((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                       FLS_MAINFUNCTION_SVC_ID, FLS_E_WRITE_FAILED );
            }
            else
#endif
            {
                if((writeResult == FLS_E_OK) && (g_WriteStartAddr > (*(g_flsConfigPtr->sectorEndAddrPtr))[g_WriteCurSectorId]))
                {
                    g_WriteCurSectorId++; /* This sector is already full, start writing to the next sector */
                }
                else
                {
                    /* This sector is not full */
                }
            }

        } while((g_WriteStartAddr <= maxWriteEndAddr) && (writeResult == FLS_E_OK));

        if(writeResult == FLS_E_FAILED)
        {
            retvalue = MEMIF_JOB_FAILED; /* Write failed */
        }
        else
        {
            if(g_WriteStartAddr > g_WriteEndAddr)
            {
                retvalue = MEMIF_JOB_OK; /* Complete all erasure tasks */
            }
            else
            {
                /* Only the current erasure task has been successfully completed */
            }
        }
    }

    return retvalue;
}

/*!
* @brief            Calculate the parameters of the read task and determine the execution result
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_OK, MEMIF_JOB_FAILED, MEMIF_JOB_PENDING
*
* @note    Non-AUTOSAR support function
*/
static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataRead(void)
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_PENDING;
    VAR( Fls_LLDResultType, AUTOMATIC ) readResult = FLS_E_FAILED;
    /* read end address */
    VAR( Fls_AddressType, AUTOMATIC ) maxReadEndAddr = 0UL;
    /* byte offset compare to the start address of current read sector */
    VAR( Fls_AddressType, AUTOMATIC ) readByteOffset = 0UL;
    /* The length of the data read this time */
    /* If cross-sector read is required, readLength is not equal to s_maxRead */
    VAR( Fls_AddressType, AUTOMATIC ) readLength = 0U;
    
    if( g_ReadStartAddr > g_ReadEndAddr ) /* read complete */
    {
        retvalue = MEMIF_JOB_OK;
    }
    else
    {
        maxReadEndAddr = (g_ReadEndAddr >= (g_ReadStartAddr + s_maxRead)) ?
                                           (g_ReadStartAddr + s_maxRead - 1U) : g_ReadEndAddr;
        do
        {
            readByteOffset = g_ReadStartAddr - (*(g_flsConfigPtr->sectorBeginAddrPtr))[g_ReadCurSectorId];

            if((*(g_flsConfigPtr->sectorEndAddrPtr))[g_ReadCurSectorId] > maxReadEndAddr)
            {
                readLength = maxReadEndAddr - g_ReadStartAddr + 1U;
            }
            else
            {
                readLength = (*(g_flsConfigPtr->sectorEndAddrPtr))[g_ReadCurSectorId] - g_ReadStartAddr + 1U;
            }

            /* renew start address to read */
            g_ReadStartAddr += readLength;

            readResult = Fls_FMC_Read( readByteOffset, readLength, s_jobDataDestPtr );

            /* renew start address of the source data */
            /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
            s_jobDataDestPtr += readLength;
#if( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN )
            if(readResult == FLS_E_FAILED)
            {
                (void)Det_ReportTransientFault((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                       FLS_MAINFUNCTION_SVC_ID, FLS_E_READ_FAILED);
            }
            else
#endif
            {
                if((readResult == FLS_E_OK) && (g_ReadStartAddr > (*(g_flsConfigPtr->sectorEndAddrPtr))[g_ReadCurSectorId]))
                {
                    g_ReadCurSectorId++; /* This sector is already full, start read to the next sector */
                }
                else
                {
                    /* This sector is not full */
                }
            }

        } while((g_ReadStartAddr <= maxReadEndAddr) && (readResult == FLS_E_OK));

        if(readResult == FLS_E_FAILED)
        {
            retvalue = MEMIF_JOB_FAILED; /* Read failed */
        }
        else
        {
            if(g_ReadStartAddr > g_ReadEndAddr)
            {
                retvalue = MEMIF_JOB_OK; /* Complete all read tasks */
            }
            else
            {
                /* Only the current read task has been successfully completed */
            }
        }
    }

    return retvalue;
}

#if( STD_ON == FLS_COMPARE_API_EN )
/*!
* @brief            Calculate the parameters of the compare task and determine the execution result
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_OK, MEMIF_BLOCK_INCONSISTENT, MEMIF_JOB_PENDING
*
* @note    Non-AUTOSAR support function
*/
static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataCompare(void)
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_PENDING;
    VAR( Fls_LLDResultType, AUTOMATIC ) compareResult = FLS_E_FAILED;
    /* compare end address */
    VAR( Fls_AddressType, AUTOMATIC ) maxCompareEndAddr = 0UL;
    /* byte offset compare to the start address of current compare sector */
    VAR( Fls_AddressType, AUTOMATIC ) compareByteOffset = 0UL;
    /* The length of the data compare this time */
    /* If cross-sector compare is required, compareLength is not equal to s_maxRead */
    VAR( Fls_AddressType, AUTOMATIC ) compareLength = 0U;
    
    if( g_CompareStartAddr > g_CompareEndAddr ) /* compare complete */
    {
        retvalue = MEMIF_JOB_OK;
    }
    else
    {
        maxCompareEndAddr = (g_CompareEndAddr >= (g_CompareStartAddr + s_maxRead)) ?
                                                 (g_CompareStartAddr + s_maxRead - 1U) : g_CompareEndAddr;
        do
        {
            compareByteOffset = g_CompareStartAddr - (*(g_flsConfigPtr->sectorBeginAddrPtr))[g_CompareCurSectorId];

            if((*(g_flsConfigPtr->sectorEndAddrPtr))[g_CompareCurSectorId] > maxCompareEndAddr)
            {
                compareLength = maxCompareEndAddr - g_CompareStartAddr + 1U;
            }
            else
            {
                compareLength = (*(g_flsConfigPtr->sectorEndAddrPtr))[g_CompareCurSectorId] - g_CompareStartAddr + 1U;
            }

            /* renew start address to compare */
            g_CompareStartAddr += compareLength;

            compareResult = Fls_FMC_Compare( compareByteOffset, compareLength, s_jobDataSrcPtr );

            /* renew start address of the source data */
            /*** @warning Fls_c_MISRA_REF1 Performing pointer arithmetic. */
            s_jobDataSrcPtr += compareLength;
#if( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN )
            if(compareResult == FLS_E_BLOCK_INCONSISTENT)
            {
                (void)Det_ReportTransientFault((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                       FLS_MAINFUNCTION_SVC_ID, FLS_E_COMPARE_FAILED);
            }
            else
#endif
            {
                if((compareResult == FLS_E_OK) && (g_CompareStartAddr > (*(g_flsConfigPtr->sectorEndAddrPtr))[g_CompareCurSectorId]))
                {
                    g_CompareCurSectorId++; /* This sector is already full, start compare to the next sector */
                }
                else
                {
                    /* This sector is not full */
                }
            }

        } while((g_CompareStartAddr <= maxCompareEndAddr) && (compareResult == FLS_E_OK));

        if(compareResult == FLS_E_BLOCK_INCONSISTENT)
        {
            retvalue = MEMIF_BLOCK_INCONSISTENT; /* Compare failed */
        }
        else
        {
            if(g_CompareStartAddr > g_CompareEndAddr)
            {
                retvalue = MEMIF_JOB_OK; /* Complete all compare tasks */
            }
            else
            {
                /* Only the current compare task has been successfully completed */
            }
        }
    }

    return retvalue;
}
#endif

#if( STD_ON == FLS_BLANKCHECK_API_EN )
/*!
* @brief            Calculate the parameters of the blank check task and determine the execution result
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_OK, MEMIF_BLOCK_INCONSISTENT, MEMIF_JOB_PENDING
*
* @note    Non-AUTOSAR support function
*/
static FUNC( MemIf_JobResultType, FLS_CODE ) Fls_StartJobDataBlankCheck(void)
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_PENDING;
    VAR( Fls_LLDResultType, AUTOMATIC ) blankcheckResult = FLS_E_FAILED;
    /* blank check end address */
    VAR( Fls_AddressType, AUTOMATIC ) maxBlankCheckEndAddr = 0UL;
    /* byte offset compare to the start address of current blank check sector */
    VAR( Fls_AddressType, AUTOMATIC ) blankcheckByteOffset = 0UL;
    /* The length of the data compare this time */
    /* If cross-sector blank check is required, blankcheckLength is not equal to s_maxRead */
    VAR( Fls_AddressType, AUTOMATIC ) blankcheckLength = 0U;

    if( g_BlankCheckStartAddr > g_BlankCheckEndAddr ) /* blank check complete */
    {
        retvalue = MEMIF_JOB_OK;
    }
    else
    {
        maxBlankCheckEndAddr = (g_BlankCheckEndAddr >= (g_BlankCheckStartAddr + s_maxRead)) ?
                                                       (g_BlankCheckStartAddr + s_maxRead - 1U) : g_BlankCheckEndAddr;
        do
        {
            blankcheckByteOffset = g_BlankCheckStartAddr - (*(g_flsConfigPtr->sectorBeginAddrPtr))[g_BlankCheckCurSectorId];

            if((*(g_flsConfigPtr->sectorEndAddrPtr))[g_BlankCheckCurSectorId] > maxBlankCheckEndAddr)
            {
                blankcheckLength = maxBlankCheckEndAddr - g_BlankCheckStartAddr + 1U;
            }
            else
            {
                blankcheckLength = (*(g_flsConfigPtr->sectorEndAddrPtr))[g_BlankCheckCurSectorId] - g_BlankCheckStartAddr + 1U;
            }

            /* renew start address to compare */
            g_BlankCheckStartAddr += blankcheckLength;

            blankcheckResult = Fls_FMC_BlankCheck( blankcheckByteOffset, blankcheckLength );

#if( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN )
            if(blankcheckResult == FLS_E_BLOCK_INCONSISTENT)
            {
                (void)Det_ReportTransientFault((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                       FLS_BLANKCHECK_SVC_ID, FLS_E_COMPARE_FAILED);
            }
            else
#endif
            {
                if((blankcheckResult == FLS_E_OK) && (g_BlankCheckStartAddr > (*(g_flsConfigPtr->sectorEndAddrPtr))[g_BlankCheckCurSectorId]))
                {
                    g_BlankCheckCurSectorId++; /* This sector is already full, start blank check to the next sector */
                }
                else
                {
                    /* This sector is not full */
                }
            }

        } while((g_BlankCheckStartAddr <= maxBlankCheckEndAddr) && (blankcheckResult == FLS_E_OK));

        if(blankcheckResult == FLS_E_BLOCK_INCONSISTENT)
        {
            retvalue = MEMIF_BLOCK_INCONSISTENT; /* Blank check failed */
        }
        else
        {
            if(g_BlankCheckStartAddr > g_BlankCheckEndAddr)
            {
                retvalue = MEMIF_JOB_OK; /* Complete all blank check tasks */
            }
            else
            {
                /* Only the current blank check task has been successfully completed */
            }
        }
    }

    return retvalue;
}
#endif

/**************************************************************************
                    GLOBAL FUNCTION
**************************************************************************/
/*!
* @brief           Performs the processing of jobs(read, write, erase and compare)
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval  None
*
* @note    AUTOSAR support function
*/
FUNC( void, FLS_CODE ) Fls_MainFunction( void )
{
    VAR( MemIf_JobResultType, AUTOMATIC ) eWorkResult = MEMIF_JOB_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if( E_NOT_OK == Fls_CheckInitializeOrNot(FLS_MAINFUNCTION_SVC_ID) )
    {
        /* do nothing */
    }
    else
#endif
    {
        if( MEMIF_JOB_PENDING == s_jobResult )
        {
            if( 1U == s_jobStart )
            {
                s_jobStart = 0U;
                g_jobResult = MEMIF_JOB_OK;  /* Reset job result */

                if( (JOB_TO_ERASE == s_jobOpnType) || (JOB_TO_WRITE == s_jobOpnType) )
                {
                    Fls_ACLoad( s_jobOpnType ); /* Load access code */
                }
                else
                {
                    /* do nothing */
                }
            }
            else
            {
                /* do nothing */
            }

            eWorkResult = g_jobResult;

            if(MEMIF_JOB_OK == eWorkResult)
            {
                if (JOB_TO_ERASE == s_jobOpnType)
                {
                    eWorkResult = Fls_StartJobErase();
                }
                else if (JOB_TO_WRITE == s_jobOpnType)
                {
                    eWorkResult = Fls_StartJobDataWrite();
                }
                else if (JOB_TO_READ == s_jobOpnType)
                {
                    eWorkResult = Fls_StartJobDataRead();
                }
            #if( STD_ON == FLS_BLANKCHECK_API_EN )
                else if (JOB_TO_CHECK_BLANK == s_jobOpnType)
                {
                    eWorkResult = Fls_StartJobDataBlankCheck();
                }
            #endif
            #if( STD_ON == FLS_COMPARE_API_EN )
                else if (JOB_TO_COMPARE == s_jobOpnType)
                {
                    eWorkResult = Fls_StartJobDataCompare();
                }
            #endif
                else
                {
                    /* do nothing */
                }
            }
            else
            {
                /* do nothing */
            }

            if( ((JOB_TO_ERASE == s_jobOpnType) || (JOB_TO_WRITE == s_jobOpnType)) && (MEMIF_JOB_PENDING != eWorkResult) )
            {
                Fls_ACUnload( s_jobOpnType );
            }
            else
            {
                /* do nothing */
            }

            s_jobResult = eWorkResult;

            if( (MEMIF_JOB_OK == eWorkResult) && (NULL_PTR != g_flsConfigPtr->jobEndNotifyPtr) )
            {
                g_flsConfigPtr->jobEndNotifyPtr();
            }
            else if ( ( (MEMIF_JOB_FAILED == eWorkResult) || (MEMIF_BLOCK_INCONSISTENT == eWorkResult) ) &&
                      (NULL_PTR != g_flsConfigPtr->jobErrorNotifyPtr) )
            {
                g_flsConfigPtr->jobErrorNotifyPtr();
            }
            else
            {
                /* do nothing */
            }
        }
        else /* No job is pending */
        {
            /* do nothing */
        }
    }
}

#if (STD_ON == FLS_VERSIONINFO_API_EN) || defined(__DOXYGEN__)
/*!
* @brief            Returns the version information of this module
*
* @param[in]        None
* @param[out]       VersioninfoPtr   Pointer to where to store the version information of this module
* @param[in,out]    None
*
* @retval  None
*
* @note    AUTOSAR support function
*/
FUNC( void, FLS_CODE ) Fls_GetVersionInfo( P2VAR( Std_VersionInfoType, AUTOMATIC, FLS_APPL_DATA ) VersioninfoPtr)
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    VAR( boolean, AUTOMATIC ) retvalue = (NULL_PTR == VersioninfoPtr)?((boolean)TRUE):((boolean)FALSE);

    if( (boolean)TRUE == retvalue )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                        FLS_GETVERSIONINFO_SVC_ID, FLS_E_PARAM_POINTER );
    }
    else
#endif
    {
        VersioninfoPtr->moduleID = (uint16)FLS_H_MODULE_ID;
        VersioninfoPtr->vendorID = (uint16)FLS_H_VENDOR_ID;
        VersioninfoPtr->sw_major_version = (uint8)FLS_H_SW_MAJOR_VERSION;
        VersioninfoPtr->sw_minor_version = (uint8)FLS_H_SW_MINOR_VERSION;
        VersioninfoPtr->sw_patch_version = (uint8)FLS_H_SW_PATCH_VERSION;
    }
}
#endif

#if (STD_ON == FLS_SETMODE_API_EN) || defined(__DOXYGEN__)
/*!
* @brief           Sets the flash driver's operation mode
*
* @param[in]       Mode    MEMIF_MODE_SLOW: Slow read / write access
*                          MEMIF_MODE_FAST: Fast read / write access
* @param[out]      None
* @param[in,out]   None
*
* @retval  None
*
* @note    AUTOSAR support function
*/
FUNC( void, FLS_CODE ) Fls_SetMode( VAR( MemIf_ModeType, AUTOMATIC ) Mode)
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if( NULL_PTR == g_flsConfigPtr )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_SETMODE_SVC_ID, FLS_E_UNINIT );
    }
    else if( MEMIF_JOB_PENDING == s_jobResult )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_SETMODE_SVC_ID, FLS_E_BUSY );
    }
    else
#endif
    {
        if ( MEMIF_MODE_FAST == Mode )
        {
            s_maxRead = g_flsConfigPtr->fastModeReadMax;
            s_maxWrite = g_flsConfigPtr->fastlModeWriteMax;
        }
        else if ( MEMIF_MODE_SLOW == Mode )
        {
            s_maxRead = g_flsConfigPtr->normalModeReadMax;
            s_maxWrite = g_flsConfigPtr->normalModeWriteMax;
        }
        else
        {
            /* do nothing */
        }
    }
}
#endif

#if (STD_ON == FLS_BLANKCHECK_API_EN)
/*!
* @brief           The function Fls_BlankCheck shall verify, whether a given memory area has been erased 
*                  but not (yet) programmed. The function shall limit the maximum number of checked flash 
*                  cells per main function cycle to the configured value FlsMaxReadNormalMode or 
*                  FlsMaxReadFastMode respectively
*
* @param[in]       TargetAddress    Address in flash memory from which the blank check should be started
* @param[in]       Length           Number of bytes to be checked for erase pattern
* @param[out]      None
* @param[in,out]   None
*
* @retval  E_OK: request for blank checking has been accepted by the module 
*          E_NOT_OK: request for blank checking has not been accepted by the module
*
* @note    AUTOSAR support function
*/
FUNC( Std_ReturnType, FLS_CODE ) Fls_BlankCheck
    ( VAR( Fls_AddressType, AUTOMATIC) TargetAddress, VAR( Fls_LengthType, AUTOMATIC) Length)
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(E_NOT_OK == Fls_CheckInitializeOrNot(FLS_BLANKCHECK_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferScope( TargetAddress, FLS_BLANKCHECK_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferAndLengthScope( TargetAddress, Length, FLS_BLANKCHECK_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else
#endif
    {
        SchM_Enter_Fls_FLS_CRITICAL_SECTION5();

        if(s_jobResult == MEMIF_JOB_PENDING)
        {
            #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
            (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_BLANKCHECK_SVC_ID, FLS_E_BUSY);
            #endif
            retValue = (Std_ReturnType)E_NOT_OK;
        }
        else /* Job blank check configuration set */
        {
            /* Current sector ID to be blank checked */
            g_BlankCheckCurSectorId = Fls_GetSectorIdxByAddr(TargetAddress);
            /* Start address to be blank checked */
            g_BlankCheckStartAddr = TargetAddress;
            /* End address to be blank checked */
            g_BlankCheckEndAddr = TargetAddress + Length - 1U;
            /* Set job type */
            s_jobOpnType = JOB_TO_CHECK_BLANK;
            /* Set the new job accepted status */
            s_jobStart = 1U;
            /* Set job result to MEMIF_JOB_PENDING, will start execute the blank check operation */
            s_jobResult = MEMIF_JOB_PENDING;
        }

        SchM_Exit_Fls_FLS_CRITICAL_SECTION5();
    }

    return retValue;
}
#endif

#if (STD_ON == FLS_COMPARE_API_EN) || defined(__DOXYGEN__)
/*!
* @brief           Compares the contents of an area of flash memory with that of an application data buffer
*
* @param[in]       TargetAddress       Source address in flash memory. 
*                                      This address offset will be added to the flash memory base address.
* @param[in]       TargetAddressPtr    Pointer to target data buffer 
* @param[in]       Length              Number of bytes to compare
* @param[out]      None
* @param[in,out]   None
*
* @retval  E_OK: compare command has been accepted
*          E_NOT_OK: compare command has not been accepted
*
* @note    AUTOSAR support function
*/
FUNC( Std_ReturnType, FLS_CODE ) Fls_Compare( VAR( Fls_AddressType, AUTOMATIC) SourceAddress,
    P2CONST( uint8, AUTOMATIC, FLS_APPL_CONST ) TargetAddressPtr, VAR( Fls_LengthType, AUTOMATIC) Length)
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(E_NOT_OK == Fls_CheckInitializeOrNot(FLS_COMPARE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferScope( SourceAddress, FLS_COMPARE_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferAndLengthScope( SourceAddress, Length, FLS_COMPARE_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferPtr(TargetAddressPtr, FLS_COMPARE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else
#endif
    {
        SchM_Enter_Fls_FLS_CRITICAL_SECTION4();

        if(s_jobResult == MEMIF_JOB_PENDING)
        {
            #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
            (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_COMPARE_SVC_ID, FLS_E_BUSY);
            #endif
            retValue = (Std_ReturnType)E_NOT_OK;
        }
        else /* Job compare configuration set */
        {
            /* Current sector ID to be compare */
            g_CompareCurSectorId = Fls_GetSectorIdxByAddr(SourceAddress);
            /* Set job data target pointer */
            s_jobDataSrcPtr = TargetAddressPtr;
            /* Start address to be compare */
            g_CompareStartAddr = SourceAddress;
            /* End address to be compare */
            g_CompareEndAddr = SourceAddress + Length - 1U;
            /* Set job type */
            s_jobOpnType = JOB_TO_COMPARE;
            /* Set the new job accepted status */
            s_jobStart = 1U;
            /* Set job result to MEMIF_JOB_PENDING, will start execute the compare operation */
            s_jobResult = MEMIF_JOB_PENDING;
        }

        SchM_Exit_Fls_FLS_CRITICAL_SECTION4();
    }

    return retValue;
}
#endif

/*!
* @brief           Reads from flash memory
*
* @param[in]       SourceAddress    Source address in flash memory.
*                                   This address offset will be added to the flash memory base address.
* @param[in]       Length           Number of bytes to read
* @param[out]      None
* @param[in,out]   None
*
* @retval  E_OK: read command has been accepted
*          E_NOT_OK: read command has not been accepted
*
* @note    AUTOSAR support function
*/
FUNC( Std_ReturnType, FLS_CODE ) Fls_Read( VAR( Fls_AddressType, AUTOMATIC) SourceAddress,
    P2VAR( uint8, AUTOMATIC, FLS_APPL_DATA ) TargetAddressPtr, VAR( Fls_LengthType, AUTOMATIC) Length)
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(E_NOT_OK == Fls_CheckInitializeOrNot(FLS_READ_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferScope( SourceAddress, FLS_READ_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferAndLengthScope( SourceAddress, Length, FLS_READ_SVC_ID ))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferPtr(TargetAddressPtr, FLS_READ_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else
#endif
    {
        SchM_Enter_Fls_FLS_CRITICAL_SECTION3();

        if(s_jobResult == MEMIF_JOB_PENDING)
        {
            #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
            (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_READ_SVC_ID, FLS_E_BUSY );
            #endif
            retValue = (Std_ReturnType)E_NOT_OK;
        }
        else /* Job read configuration set */
        {
            /* Current sector ID to be read */
            g_ReadCurSectorId = Fls_GetSectorIdxByAddr(SourceAddress);
            /* Set job data target pointer */
            s_jobDataDestPtr = TargetAddressPtr;
            /* Start address to be read */
            g_ReadStartAddr = SourceAddress;
            /* End address to be read */
            g_ReadEndAddr = SourceAddress + Length - 1U;
            /* Set job type */
            s_jobOpnType = JOB_TO_READ;
            /* Set the new job accepted status */
            s_jobStart = 1U;
            /* Set job result to MEMIF_JOB_PENDING, will start execute the read operation */
            s_jobResult = MEMIF_JOB_PENDING;
        }

        SchM_Exit_Fls_FLS_CRITICAL_SECTION3();
    }

    return retValue;
}

#if (STD_ON == FLS_GETJOBRESULT_API_EN) ||  defined (__DOXYGEN__)
/*!
* @brief            Returns the result of the last job.
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_JOB_FAILED, MEMIF_JOB_OK
*
* @note    AUTOSAR support function
*/
FUNC( MemIf_JobResultType, FLS_CODE ) Fls_GetJobResult( void )
{
    VAR( MemIf_JobResultType, AUTOMATIC ) retvalue = MEMIF_JOB_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    retvalue = (NULL_PTR == g_flsConfigPtr) ? MEMIF_JOB_FAILED : MEMIF_JOB_OK;

    if ( MEMIF_JOB_FAILED == retvalue )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_GETJOBRESULT_SVC_ID, FLS_E_UNINIT );
    }
    else
#endif
    {
        retvalue = s_jobResult;
    }

    return retvalue;
}
#endif

#if((STD_ON == FLS_GETSTATUS_API_EN) || defined (__DOXYGEN__))
/*!
* @brief            Returns the driver state
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  MEMIF_UNINIT, MEMIF_BUSY, MEMIF_IDLE
*
* @note    AUTOSAR support function
*/
FUNC( MemIf_StatusType, FLS_CODE ) Fls_GetStatus( void )
{
    VAR( MemIf_StatusType, AUTOMATIC ) retvalue = MEMIF_IDLE;

    retvalue = (MEMIF_JOB_PENDING == s_jobResult) ? MEMIF_BUSY : MEMIF_IDLE;

    retvalue = (NULL_PTR == g_flsConfigPtr) ? MEMIF_UNINIT : retvalue;

    return retvalue;
}
#endif

#if (STD_ON == FLS_CANCEL_API_EN) || defined(__DOXYGEN__)
/*!
* @brief            Cancels an ongoing job
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*
* @note    AUTOSAR support function
*/
FUNC( void, FLS_CODE ) Fls_Cancel( void )
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if( NULL_PTR == g_flsConfigPtr )
    {
        (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_CANCEL_SVC_ID, FLS_E_UNINIT );
    }
    else
#endif
    {
        if( MEMIF_JOB_PENDING == s_jobResult)
        {
            if (MEMIF_JOB_PENDING == g_jobResult)
            {
                    Fls_FMC_Cancel();
            }
            else
            {
                g_jobResult = MEMIF_JOB_CANCELED;
            }

            if ((JOB_TO_ERASE == s_jobOpnType) || (JOB_TO_WRITE == s_jobOpnType))
            {
                 Fls_ACUnload( s_jobOpnType );
            }
            else
            {
                /* do nothing */
            }

            s_jobResult = (MEMIF_JOB_CANCELED == g_jobResult)? MEMIF_JOB_CANCELED : s_jobResult ;

            /* Check FlsJobErrorNotification */
            if( NULL_PTR != g_flsConfigPtr->jobErrorNotifyPtr )
            {
                g_flsConfigPtr->jobErrorNotifyPtr();
            }
            else
            {
                /* do nothing */
            }
        }
        else
        {
            /* do nothing */
        }
    }
}
#endif

/*!
* @brief            Writes one or more complete flash pages
*
* @param[in]        TargetAddress       Target address in flash memory.
*                                       This address offset will be added to the flash memory base address.
* @param[in]        SourceAddressPtr    Pointer to source data buffer
* @param[in]        Length              Number of bytes to write
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK: write command has been accepted
*          E_NOT_OK: write command has not been accepted
*
* @note    AUTOSAR support function
*/
FUNC( Std_ReturnType, FLS_CODE ) Fls_Write( VAR( Fls_AddressType, AUTOMATIC) TargetAddress,
    P2CONST( uint8, AUTOMATIC, FLS_APPL_CONST ) SourceAddressPtr, VAR( Fls_LengthType, AUTOMATIC) Length)
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(E_NOT_OK == Fls_CheckInitializeOrNot(FLS_WRITE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckStartAddrAlign(TargetAddress, FLS_WRITE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckEndAddrAlign(TargetAddress, Length, FLS_WRITE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckBufferPtr(SourceAddressPtr, FLS_WRITE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckCrossHalfPage(TargetAddress, Length))
    {
        retValue = E_NOT_OK;
    }
    else
#endif
    {
        SchM_Enter_Fls_FLS_CRITICAL_SECTION2();

        if(s_jobResult == MEMIF_JOB_PENDING)
        {
            #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
            (void) Det_ReportError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_WRITE_SVC_ID, FLS_E_BUSY );
            #endif
            retValue = (Std_ReturnType)E_NOT_OK;
        }
        else /* Job write configuration set */
        {
            /* Current sector ID to be writted */
            g_WriteCurSectorId = Fls_GetSectorIdxByAddr(TargetAddress);
            /* Set job data source pointer */
            s_jobDataSrcPtr = SourceAddressPtr;
            /* Start address to be writted */
            g_WriteStartAddr = TargetAddress;
            /* End address to be writted */
            g_WriteEndAddr = TargetAddress + Length - 1U;
            /* Set job type */
            s_jobOpnType = JOB_TO_WRITE;
            /* Set the new job accepted status */
            s_jobStart = 1U;
            /* Set job result to MEMIF_JOB_PENDING, will start execute the write operation */ 
            s_jobResult = MEMIF_JOB_PENDING;
        }

        SchM_Exit_Fls_FLS_CRITICAL_SECTION2();
    }

    return retValue;
}

/*!
* @brief            Erases flash sector(s)
*
* @param[in]        TargetAddress    Target address in flash memory.
*                                    This address offset will be added to the flash memory base address.
* @param[in]        Length           Number of bytes to erase
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK: erase command has been accepted 
*          E_NOT_OK: erase command has not been accepted
*
* @note    AUTOSAR support function
*/
FUNC( Std_ReturnType, FLS_CODE ) Fls_Erase
    ( VAR( Fls_AddressType, AUTOMATIC) TargetAddress, VAR( Fls_LengthType, AUTOMATIC) Length)
{
    VAR( Std_ReturnType, AUTOMATIC ) retValue = (Std_ReturnType)E_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(E_NOT_OK == Fls_CheckInitializeOrNot(FLS_ERASE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckStartAddrAlign(TargetAddress, FLS_ERASE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else if(E_NOT_OK == Fls_CheckEndAddrAlign(TargetAddress, Length, FLS_ERASE_SVC_ID))
    {
        retValue = E_NOT_OK;
    }
    else
#endif
    {
        SchM_Enter_Fls_FLS_CRITICAL_SECTION1();

        if(s_jobResult == MEMIF_JOB_PENDING)
        {
            #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
            (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_ERASE_SVC_ID, FLS_E_BUSY);
            #endif
            retValue = (Std_ReturnType)E_NOT_OK;
        }
        else /* Job erase configuration set */
        {
            /* Start sector ID to be erased */
            g_EraseSectorStartId = Fls_GetSectorIdxByAddr( TargetAddress );
            /* End sector ID to be erased */
            g_EraseSectorEndId = Fls_GetSectorIdxByAddr(( TargetAddress + Length ) - 1U );
            /* Set job type */
            s_jobOpnType = JOB_TO_ERASE;
            /* Set the new job accepted status */
            s_jobStart = 1U;
            /* Set job result to MEMIF_JOB_PENDING, will start execute the erase operation */
            s_jobResult = MEMIF_JOB_PENDING;
        }

        SchM_Exit_Fls_FLS_CRITICAL_SECTION1();
    }

    return retValue;
}

/*!
* @brief            Initializes the Flash Driver
*
* @param[in]        ConfigPtr    Pointer to flash driver configuration set
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*
* @note    AUTOSAR support function
*/
FUNC( void, FLS_CODE ) Fls_Init( P2CONST( Fls_ConfigType, AUTOMATIC, FLS_APPL_CONST ) ConfigPtr )
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if (NULL_PTR == ConfigPtr)   /* in PostBuild  mode, ConfigPtr should not be NULL_PTR */
    {
        (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_INIT_SVC_ID, FLS_E_PARAM_CONFIG);
    }
    else if(MEMIF_JOB_PENDING == s_jobResult) /* Fls in busy */
    {
        (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_INIT_SVC_ID, FLS_E_BUSY);
    }
    else
#endif
    {
        g_flsConfigPtr = ConfigPtr; /* in PostBuild mode, g_flsConfigPtr struct is ConfigPtr struct */

        /* Set the transfer mode parameters */
        if (MEMIF_MODE_SLOW == g_flsConfigPtr->memIfDefaultMode)
        {
           s_maxRead = g_flsConfigPtr->normalModeReadMax;
           s_maxWrite = g_flsConfigPtr->normalModeWriteMax;
        }
        else
        {
           s_maxRead = g_flsConfigPtr->fastModeReadMax;
           s_maxWrite = g_flsConfigPtr->fastlModeWriteMax;
        }

        Fls_FMC_Init(); /* Go to register layer */

        s_jobResult = (MEMIF_JOB_FAILED == g_jobResult) ? MEMIF_JOB_FAILED : MEMIF_JOB_OK;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
        g_flsConfigPtr = (MEMIF_JOB_FAILED == g_jobResult) ? ((const Fls_ConfigType*)NULL_PTR) : g_flsConfigPtr;
#endif

    }
}

#if(STD_ON == FLS_WRITE_OPTION_BYTE_API_EN)
/*!
* @brief            Program Option Byte Area.
*
* @param[in]        SourceAddressPtr    Target data
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*
* @note    Non-AUTOSAR support function
*/
FUNC(void, FLS_CODE) Fls_WriteOptionByte(P2CONST(uint32, AUTOMATIC, FLS_APPL_CONST) SourceAddressPtr)
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(NULL_PTR == SourceAddressPtr)
    {
        (void)Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                      FLS_WRITEOPTIONBYTE_SVC_ID, FLS_E_PARAM_POINTER);
    }
    else
#endif
    {
        Fls_FMC_WriteOptionByte(SourceAddressPtr);
    }
}
#endif

/*!
* @brief            Read Option Byte Register.
*
* @param[in]        RegId    Option Byte Register Id
* @param[out]       None
* @param[in,out]    None
*
* @retval  uint8    register value
*
* @note    Non-AUTOSAR support function
*/
FUNC(uint8, FLS_CODE) Fls_ReadOptionByte(VAR(Fls_OptByteReadRegIdType, AUTOMATIC) RegId)
{
    VAR(uint8, AUTOMATIC) regValue = 0U;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if((OPTBYTE_READPORT_REG != RegId) && (OPTBYTE_UOB_REG != RegId) && (OPTBYTE_DATA0_REG != RegId) && 
       (OPTBYTE_DATA1_REG != RegId) && (OPTBYTE_WRP0_REG != RegId) && (OPTBYTE_WRP1_REG != RegId) &&
       (OPTBYTE_WRP2_REG != RegId) && (OPTBYTE_WRP3_REG != RegId) && (OPTBYTE_WRP4_REG != RegId) &&
       (OPTBYTE_WRP5_REG != RegId) && (OPTBYTE_WRP6_REG != RegId) && (OPTBYTE_WRP7_REG != RegId))
    {
        (void)Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                      FLS_READOPTIONBYTE_SVC_ID, FLS_E_PARAM_DATA);
    }
    else
#endif
    {
        regValue = (uint8)Fls_FMC_ReadOptByteReg(RegId);
    }

    return (uint8)regValue;
}

#if(STD_ON == FLS_ERASE_PFLASH_DFLASH_API_EN)
/*!
* @brief            Select erase area
*
* @param[in]        TargetFlash    flash type (ONLY_EARSE_PFLASH, ONLY_EARSE_DFLASH, EARSE_PFLASH_DFLASH)
* @param[out]       None
* @param[in,out]    None
*
* @retval  E_OK: erase successfully
*          E_NOT_OK: erase failed
*
* @note    Non-AUTOSAR support function
*/
FUNC(Std_ReturnType, FLS_CODE) Fls_ErasePflashDflash(VAR(Fls_EraseFlashType, AUTOMATIC) TargetFlash)
{
    VAR(Std_ReturnType, AUTOMATIC) retValue = (Std_ReturnType)E_NOT_OK;
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if((ONLY_EARSE_PFLASH != TargetFlash) && (ONLY_EARSE_DFLASH != TargetFlash) && (EARSE_PFLASH_DFLASH != TargetFlash))
    {
        (void)Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                      FLS_ERASEPFLASHDFLASH_SVC_ID, FLS_E_PARAM_DATA);
        retValue = (Std_ReturnType)E_NOT_OK;
    }
    else
#endif
    {
        retResult = Fls_FMC_ErasePflashDflash(TargetFlash);

        retValue = (FLS_E_FAILED == retResult) ? E_NOT_OK : E_OK;
    }

    return retValue;
}
#endif

/*!
* @brief            Get Chip Id
*
* @param[in]        None
* @param[out]       ChipIdPtr    store chip id information
* @param[in,out]    None
*
* @retval  None
*
* @note    Non-AUTOSAR support function
*/
FUNC(void, FLS_CODE) Fls_GetChipId(P2VAR(Fls_ChipIdType, AUTOMATIC, FLS_APPL_DATA) ChipIdPtr)
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(NULL_PTR == ChipIdPtr)
    {
        (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_GETCHIPID_SVC_ID, FLS_E_PARAM_POINTER);
    }
    else
#endif
    {
        ChipIdPtr->u_id_0 = (uint32)Fls_Signature_GetChipId0();
        ChipIdPtr->u_id_1 = (uint32)Fls_Signature_GetChipId1();
        ChipIdPtr->u_id_2 = (uint32)Fls_Signature_GetChipId2();
    }
}

/*!
* @brief            Get Memory Capacity
*
* @param[in]        Memory    INTERNAL_PFLASH or INTERNAL_DFLASH
* @param[out]       None
* @param[in,out]    None
*
* @retval  flash capacity
*
* @note    Non-AUTOSAR support function
*/
FUNC(uint16, FLS_CODE) Fls_GetMemoryCapacity(VAR(Fls_InternalFlashType, AUTOMATIC) Memory)
{
    VAR(uint16, AUTOMATIC) capacity = 0U;

#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if((INTERNAL_PFLASH != Memory) && (INTERNAL_DFLASH != Memory))
    {
        (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_GETMEMORYCAPACITY_SVC_ID, FLS_E_PARAM_DATA);
    }
    else
#endif
    {
        capacity = (uint16)Fls_Signature_GetMemoryCapacity(Memory);
    }

    return (uint16)capacity;
}

/*!
* @brief            Get Chip product version and series number
*
* @param[in]        None
* @param[out]       ChipSeriesPtr    store chip product version and series number
* @param[in,out]    None
*
* @retval  None
*
* @note    Non-AUTOSAR support function
*/
FUNC(void, FLS_CODE) Fls_GetChipProductSeries(P2VAR(Fls_ChipProductSeriesType, AUTOMATIC, FLS_APPL_DATA) ChipSeriesPtr)
{
#if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
    if(NULL_PTR == ChipSeriesPtr)
    {
        (void) Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                       FLS_GETCHIPPRODUCTSERIES_SVC_ID, FLS_E_PARAM_POINTER);
    }
    else
#endif
    {
        ChipSeriesPtr->version  = (uint8)Fls_Signature_GetChipProduct();
        ChipSeriesPtr->series_1 = (uint8)Fls_Signature_GetChipSeries1();
        ChipSeriesPtr->series_2 = (uint8)Fls_Signature_GetChipSeries2();
    }
}

/**@} end of group FLS_Fuctions */

#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"

#ifdef __cplusplus
}
#endif

/**@} end of group FLS_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */
