/**
*     Copyright (c) 2022, Nsing Technologies Pte. Ltd.
*
*     All rights reserved.
*
*     This software is the exclusive property of Nsing Technologies Pte. Ltd. (Hereinafter
* referred to as Nsing). This software, and the product of Nsing described herein
* (Hereinafter referred to as the Product) are owned by Nsing under the laws and treaties
* of the People's Republic of China and other applicable jurisdictions worldwide.
*
*     Nsing does not grant any license under its patents, copyrights, trademarks, or other
* intellectual property rights. Names and brands of third party may be mentioned or referred
* thereto (if any) for identification purposes only.
*
*     Nsing reserves the right to make changes, corrections, enhancements, modifications, and
* improvements to this software at any time without notice. Please contact Nsing and obtain
* the latest version of this software before placing orders.

*     Although Nsing has attempted to provide accurate and reliable information, Nsing assumes
* no responsibility for the accuracy and reliability of this software.
*
*     It is the responsibility of the user of this software to properly design, program, and test
* the functionality and safety of any application made of this information and any resulting product.
* In no event shall Nsing be liable for any direct, indirect, incidental, special,exemplary, or
* consequential damages arising in any way out of the use of this software or the Product.
*
*     Nsing Products are neither intended nor warranted for usage in systems or equipment, any
* malfunction or failure of which may cause loss of human life, bodily injury or severe property
* damage. Such applications are deemed, "Insecure Usage".
*
*     All Insecure Usage shall be made at user's risk. User shall indemnify Nsing and hold Nsing
* harmless from and against all claims, costs, damages, and other liabilities, arising from or related
* to any customer's Insecure Usage.

*     Any express or implied warranty with regard to this software or the Product, including,but not
* limited to, the warranties of merchantability, fitness for a particular purpose and non-infringement
* are disclaimed to the fullest extent permitted by law.

*     Unless otherwise explicitly permitted by Nsing, anyone may not duplicate, modify, transcribe
* or otherwise distribute this software for any purposes, in whole or in part.
*
*     Nsing products and technologies shall not be used for or incorporated into any products or systems
* whose manufacture, use, or sale is prohibited under any applicable domestic or foreign laws or regulations.
* User shall comply with any applicable export control laws and regulations promulgated and administered by
* the governments of any countries asserting jurisdiction over the parties or transactions.
**/

/**
 *\*\file system_n32g003.c
 *\*\author Nsing
 *\*\version v1.0.0
 *\*\copyright Copyright (c) 2022, Nsing Technologies Pte. Ltd. All rights reserved.
 **/
#include "n32g003_flash.h"

/**
 *\*\name    FLASH_Latency_Set
 *\*\fun     Sets the code latency value.
 *\*\note    This function can be used for N32G003 devices.
 *\*\param   flash_latency :
 *\*\            - FLASH_LATENCY_0    FLASH Zero Latency cycle, 0 < HCLK <= 24MHz
 *\*\            - FLASH_LATENCY_1    FLASH One Latency cycle, 24MHz < HCLK<= 48MHz
 *\*\return  none
 **/

void FLASH_Latency_Set(uint32_t flash_latency)
{
    uint32_t temp_value = 0;

    /* Read the AC register */
    temp_value = FLASH->AC;

    /* Sets the Latency value */
    temp_value &= (~FLASH_LATENCY_MASK);
    temp_value |= flash_latency;

    /* Write the AC register */
    FLASH->AC = temp_value;
}

/**
 *\*\name    FLASH_Latency_Get
 *\*\fun     Get the code latency value.
 *\*\note    This function can be used for N32G003 devices.
 *\*\param   none
 *\*\return  FLASH_LATENCY :
 *\*\            - FLASH_LATENCY_0    FLASH Zero Latency cycle, 0 < HCLK <= 24MHz
 *\*\            - FLASH_LATENCY_1    FLASH One Latency cycle, 24MHz < HCLK<= 48MHz
 **/
uint8_t FLASH_Latency_Get(void)
{
    /* Read the AC register */
    return (uint8_t)(FLASH->AC & FLASH_LATENCY_MASK);
}

/**
 *\*\name    FLASH_Prefetch_Buffer_Enable
 *\*\fun     Enables the Prefetch Buffer.
 *\*\note    This function can be used for N32G003 devices.
 *\*\param   none
 *\*\return  none
 **/
void FLASH_Prefetch_Buffer_Enable(void)
{
    /* Enable the Prefetch Buffer */
    FLASH->AC |= FLASH_PREFETCHBUF_EN;
}

/**
 *\*\name    FLASH_Prefetch_Buffer_Disable
 *\*\fun     Disables the Prefetch Buffer.
 *\*\note    This function can be used for N32G003 devices.
 *\*\param   none
 *\*\return  none
 **/
void FLASH_Prefetch_Buffer_Disable(void)
{
    /* Disable the Prefetch Buffer */
    FLASH->AC &= FLASH_PREFETCHBUF_DIS;
}

/**
 *\*\name   FLASH_Unlock
 *\*\fun    Unlocks the FLASH Program Erase Controller.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return none
 **/
void FLASH_Unlock(void)
{
    FLASH->KEY = FLASH_KEY1;
    FLASH->KEY = FLASH_KEY2;
}

/**
 *\*\name   FLASH_Lock
 *\*\fun    Locks the FLASH Program Erase Controller.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return none
 **/
void FLASH_Lock(void)
{
    FLASH->CTRL |= FLASH_CTRL_SET_LOCK;
}

/**
 *\*\name   Option_Bytes_Unlock
 *\*\fun    Unlocks the Option_Bytes Program Erase Controller.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return none
 **/
void Option_Bytes_Unlock(void)
{
    FLASH->OPTKEY = FLASH_KEY1;
    FLASH->OPTKEY = FLASH_KEY2;
}

/**
 *\*\name   Option_Bytes_Lock
 *\*\fun    Locks the Option_Bytes Program Erase Controller.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return none
 **/
void Option_Bytes_Lock(void)
{
    /* Set the FLASH_CTRL_SET_OPTWE Bit to lock */
    FLASH->CTRL &= (~FLASH_CTRL_SET_OPTWE);
}

/**
 *\*\name   Option_Bytes_Lock_Status_Get
 *\*\fun    Get the Option Bytes lock status.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FlagStatus :
 *\*\            - SET
 *\*\            - RESET
 **/
FlagStatus Option_Bytes_Lock_Status_Get(void)
{
    if ((FLASH->CTRL & FLASH_CTRL_SET_OPTWE) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_One_Page_Erase
 *\*\fun    Erases a specified FLASH page.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  page_address :
 *\*\            - It ranges from 0x08000000 to 0x0800FFFF
 *\*\return FLASH_STS :
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_One_Page_Erase(uint32_t page_address)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        /* if the previous operation is completed, proceed to erase the page */
        FLASH->CTRL |= FLASH_CTRL_SET_PER;
        FLASH->ADD = page_address;
        FLASH->CTRL |= FLASH_CTRL_SET_START;

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

        /* Disable the PER Bit */
        FLASH->CTRL &= FLASH_CTRL_RESET_PER;
    }
    else
    {
        /*No process*/
    }

    /* Return the Erase status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Mass_Erase
 *\*\fun    Erases all FLASH pages.
 *\*\note   This function can be used for all N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Mass_Erase(void)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        /* if the previous operation is completed, proceed to erase all pages */
        FLASH->CTRL |= FLASH_CTRL_SET_MER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

        /* Disable the MER Bit */
        FLASH->CTRL &= FLASH_CTRL_RESET_MER;
    }
    else
    {
        /*No process*/
    }

    /* Return the Erase status_value */
    return status_value;
}

/**
 *\*\name   FLASH_48Page_Mass_Erase
 *\*\fun    Erases first 48 pages FLASH.
 *\*\note   This function can be used for all N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_48Page_Mass_Erase(void)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        /* if the previous operation is completed, proceed to erase all pages */
        FLASH->CTRL |= FLASH_CTRL_SET_MMER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

        /* Disable the MER Bit */
        FLASH->CTRL &= FLASH_CTRL_RESET_MMER;
    }
    else
    {
        /*No process*/
    }

    /* Return the Erase status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Word_Program
 *\*\fun    Programs a word at a specified address.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  address :
 *\*\            - It ranges from 0x08000000 to 0x080075FF
 *\*\param  data :
 *\*\            - It ranges from 0x00000000 to 0xFFFFFFFF
 *\*\return FLASH_STS :
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_ERR_ADD
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Word_Program(uint32_t address, uint32_t data)
{
    FLASH_STS status_value = FLASH_EOP;

    if ((address & FLASH_WORD_LENGTH) != RESET)
    {
        /* The programming address is not a multiple of 4 */
        return FLASH_ERR_ADD;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        /* if the previous operation is completed, proceed to program the new word */
        FLASH->CTRL |= FLASH_CTRL_SET_PG;

        *(__IO uint32_t *)address = (uint32_t)data;
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);

        /* Disable the PG Bit */
        FLASH->CTRL &= FLASH_CTRL_RESET_PG;
    }
    else
    {
        /*No process*/
    }

    /* Return the Program status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_Erase
 *\*\fun    Erases the FLASH option bytes.
 *\*\note   This functions erases all option bytes except the Read protection (RDP).
 *\*\       This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_ERR_RDP2
 *\*\            - FLASH_ERR_ADD
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Option_Bytes_Erase(void)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();

        /* if the previous operation is completed, proceed to erase the option bytes */
        FLASH->CTRL |= FLASH_CTRL_SET_OPTER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

        if (status_value == FLASH_EOP)
        {
            /* Clears the FLASH's pending flags */
            FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);

            /* if the erase operation is completed, disable the OPTER Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
        }
        else
        {
            if (status_value != FLASH_TIMEOUT)
            {
                /* Disable the OPTER Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            }
            else
            {
                /*No process*/
            }
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the erase status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_User_RDP1_Program
 *\*\fun    Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_PD /
 *\*\       LOCK_BOOT / PA0_NRST / RDP1.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_rdp1 :
 *\*\        - FLASH_OB_RDP1_ENABLE
 *\*\        - FLASH_OB_RDP1_DISABLE
 *\*\param  option_byte_iwdg :
 *\*\        - FLASH_OB_IWDG_SW Software IWDG selected
 *\*\        - FLASH_OB_IWDG_HW Hardware IWDG selected
 *\*\param  option_byte_stop :
 *\*\        - FLASH_OB_STOP_NORST No reset generated when entering in STOP
 *\*\        - FLASH_OB_STOP_RST Reset generated when entering in STOP
 *\*\param  option_byte_PD :
 *\*\        - FLASH_OB_PD_NORST No reset generated when entering in PD
 *\*\        - FLASH_OB_PD_RST Reset generated when entering in PD
 *\*\param  option_byte_lock_boot :
 *\*\        - FLASH_OB_LOCK_BOOT First 3KB FLASH LOCK
 *\*\        - FLASH_OB_NOLOCK_BOOT First 3KB FLASH NOLOCK
 *\*\param  option_byte_PA0_NRST :
 *\*\        - FLASH_OB_PA0_IO PA0 is general pin
 *\*\        - FLASH_OB_PA0_NRST PA0 is RESET pin
 *\*\return FLASH_STS :
 *\*\        - FLASH_BUSY
 *\*\        - FLASH_ERR_PG
 *\*\        - FLASH_ERR_WRP
 *\*\        - FLASH_EOP
 *\*\        - FLASH_ERR_RDP2
 *\*\        - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Option_Bytes_User_RDP1_Program(uint8_t option_byte_rdp1, uint16_t option_byte_iwdg,
                                               uint16_t option_byte_stop, uint16_t option_byte_PD,
                                               uint16_t option_byte_lock_boot, uint16_t option_byte_PA0_NRST)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    Option_Bytes_Unlock();

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        /* Enable the Option Bytes Programming operation */
        FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
        /* Restore the last read protection Option Byte value */
        OBT->USER_RDP =
            (uint32_t)option_byte_rdp1 | (((uint32_t)(option_byte_iwdg | option_byte_stop | option_byte_PD | option_byte_lock_boot | option_byte_PA0_NRST)) << FLASH_USER_RDP_OFFSET);

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);
        if (status_value != FLASH_TIMEOUT)
        {
            /* if the program operation is completed, disable the OPTPG Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
        }
        else
        {
            /*No process*/
        }
    }
    else
    {
        /*No process*/
    }

    /* Return the Option Byte program status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_DATA_Program
 *\*\fun    Programs a half word at a specified Option Byte Data0 and Data1.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_data0:
 *\*\                - 0x00 to 0xFF
 *\*\param  option_byte_data1:
 *\*\                - 0x00 to 0xFF
 *\*\return FLASH_STS: The returned value can be:
 *\*\                - FLASH_BUSY
 *\*\                - FLASH_ERR_PG
 *\*\                - FLASH_ERR_WRP
 *\*\                - FLASH_EOP
 *\*\                - FLASH_ERR_RDP2
 *\*\                - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Option_Bytes_DATA_Program(uint8_t option_byte_data0, uint8_t option_byte_data1)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        /* Enables the Option Bytes Programming operation */
        FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
        OBT->Data1_Data0 = (((uint32_t)option_byte_data1) << FLASH_DATA0_DATA1_OFFSET) | ((uint32_t)option_byte_data0);

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);
        if (status_value != FLASH_TIMEOUT)
        {
            /* if the program operation is completed, disable the OPTPG Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
        }
        else
        {
            /*No process*/
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the Option Byte Data Program status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_User2_User3_Program
 *\*\fun    Programs a half word at a specified Option Byte USER2 and USER3.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_user2:
 *\*\                - 0x00 to 0xFF  LVR filter control count value
 *\*\param  option_byte_LVR_cnt :
 *\*\                - 0x00 to 0x0F  LVR gear selection
 *\*\param  option_byte_LVR :
 *\*\                - FLASH_OB_USER_LVR_ENABLE LVR enable
 *\*\                - FLASH_OB_USER_LVR_DISABLE LVR disable
 *\*\param  option_byte_LVR_filter :
 *\*\                - FLASH_OB_USER_LVRFIL_ENABLE LVR filter enable
 *\*\                - FLASH_OB_USER_LVRFIL_DISABLE LVR filter disable
 *\*\return FLASH_STS: The returned value can be:
 *\*\                - FLASH_BUSY
 *\*\                - FLASH_ERR_PG
 *\*\                - FLASH_ERR_WRP
 *\*\                - FLASH_EOP
 *\*\                - FLASH_ERR_RDP2
 *\*\                - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Option_Bytes_User2_User3_Program(uint8_t option_byte_user2, uint8_t option_byte_LVR_cnt,
                                                 uint8_t option_byte_LVR, uint8_t option_byte_LVR_filter)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);
    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }
    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        /* Enables the Option Bytes Programming operation */
        FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
        OBT->USER3_USER2 = (uint32_t)option_byte_user2 | (((uint32_t)(option_byte_LVR_cnt | option_byte_LVR | option_byte_LVR_filter)) << FLASH_USER2_USER3_OFFSET);

        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);
        if (status_value != FLASH_TIMEOUT)
        {
            /* if the program operation is completed, disable the OPTPG Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
        }
        else
        {
            /*No process*/
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the Option Byte Data Program status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_User4_RDP2_Program
 *\*\fun    Programs a half word at a specified Option Byte Data address.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_rdp2:
 *\*\            - FLASH_OB_RDP2_ENABLE
 *\*\            - FLASH_OB_RDP2_DISABLE
 *\*\param  option_byte_user4:
 *\*\            - 0x00 to 0xFF
 *\*\return FLASH_STS: The returned value can be:
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_ERR_RDP2
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Option_Bytes_User4_RDP2_Program(uint8_t option_byte_rdp2, uint8_t option_byte_user4)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        /* Enables the Option Bytes Programming operation */
        FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
        OBT->USER4_RDP2 = (((uint32_t)option_byte_user4) << FLASH_DATA0_DATA1_OFFSET) | ((uint32_t)option_byte_rdp2);
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(PROGRAM_TIMEOUT);
        if (status_value != FLASH_TIMEOUT)
        {
            /* if the program operation is completed, disable the OPTPG Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
        }
        else
        {
            /*No process*/
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the Option Byte Data Program status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Read_Out_Protection_L1_Enable
 *\*\fun    Enables the read out protection.
 *\*\note   If the user has already programmed the other option bytes before calling
 *\*\       this function, he must re-program them since this function erases all option bytes.
 *\*\       This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\        - FLASH_BUSY
 *\*\        - FLASH_ERR_PG
 *\*\        - FLASH_ERR_WRP
 *\*\        - FLASH_EOP
 *\*\        - FLASH_ERR_RDP2
 *\*\        - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Read_Out_Protection_L1_Enable(void)
{
    uint32_t user_temp;
    FLASH_STS status_value = FLASH_EOP;

    user_temp = ((FLASH_OB_USER_MSK & FLASH->OB) << FLASH_OB_TO_USER_OFFSET);

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        FLASH->CTRL |= FLASH_CTRL_SET_OPTER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);
        if (status_value == FLASH_EOP)
        {
            /* Clears the FLASH's pending flags */
            FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);

            /* if the erase operation is completed, disable the OPTER Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            /* Enable the Option Bytes Programming operation */
            FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
            /*enable new state of the ReadOut Protection*/
            OBT->USER_RDP = (FLASH_USER_MASK & user_temp);
            /* Wait for last operation to be completed */
            status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

            if (status_value != FLASH_TIMEOUT)
            {
                /* if the program operation is completed, disable the OPTPG Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
            }
            else
            {
                /*No process*/
            }
        }
        else
        {
            if (status_value != FLASH_TIMEOUT)
            {
                /* Disable the OPTER Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            }
            else
            {
                /*No process*/
            }
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the protection operation status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Read_Out_Protection_L1_Disable
 *\*\fun    Disables the read out protection.
 *\*\note   If the user has already programmed the other option bytes before calling
 *\*\       this function, he must re-program them since this function erases all option bytes.
 *\*\       This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\        - FLASH_BUSY
 *\*\        - FLASH_ERR_PG
 *\*\        - FLASH_ERR_WRP
 *\*\        - FLASH_EOP
 *\*\        - FLASH_ERR_RDP2
 *\*\        - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Read_Out_Protection_L1_Disable(void)
{
    uint32_t user_temp;
    FLASH_STS status_value = FLASH_EOP;

    user_temp = ((FLASH_OB_USER_MSK & FLASH->OB) << FLASH_OB_TO_USER_OFFSET);

    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        FLASH->CTRL |= FLASH_CTRL_SET_OPTER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);
        if (status_value == FLASH_EOP)
        {
            /* Clears the FLASH's pending flags */
            FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);

            /* if the erase operation is completed, disable the OPTER Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            /* Enable the Option Bytes Programming operation */
            FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;
            /* Disables the read out protection */
            OBT->USER_RDP = ((FLASH_L1_RDP_KEY & FLASH_RDP1_MASK) | user_temp);
            /* Wait for last operation to be completed */
            status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

            if (status_value != FLASH_TIMEOUT)
            {
                /* if the program operation is completed, disable the OPTPG Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
            }
            else
            {
                /*No process*/
            }
        }
        else
        {
            if (status_value != FLASH_TIMEOUT)
            {
                /* Disable the OPTER Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            }
            else
            {
                /*No process*/
            }
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the protection operation status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Read_Out_Protection_L2_Enable
 *\*\fun    Enables or disables the read out protection L2.
 *\*\note   If the user has already programmed the other option bytes before calling
 *\*\       this function, he must re-program them since this function erases all option bytes.
 *\*\       This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\        - FLASH_BUSY
 *\*\        - FLASH_ERR_PG
 *\*\        - FLASH_ERR_WRP
 *\*\        - FLASH_EOP
 *\*\        - FLASH_ERR_RDP2
 *\*\        - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Read_Out_Protection_L2_Enable(void)
{
    uint32_t user_temp;
    FLASH_STS status_value = FLASH_EOP;

    user_temp = ((FLASH_OB_USER_MSK & FLASH->OB) << FLASH_OB_TO_USER_OFFSET);

    /* Get the actual read protection L1 Option Byte value */
    if (FLASH_Read_Out_Protection_Status_Get() == RESET)
    {
        user_temp |= (FLASH_L1_RDP_KEY & FLASH_RDP1_MASK);
    }
    else
    {
        /*No process*/
    }
    /* Get the actual read protection L2 Option Byte value */
    if (FLASH_Read_Out_Protection_L2_Status_Get() != RESET)
    {
        return FLASH_ERR_RDP2;
    }
    else
    {
        /*No process*/
    }

    /* Clears the FLASH's pending flags */
    FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);
    /* Wait for last operation to be completed */
    status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

    if (status_value == FLASH_EOP)
    {
        Option_Bytes_Unlock();
        FLASH->CTRL |= FLASH_CTRL_SET_OPTER;
        FLASH->CTRL |= FLASH_CTRL_SET_START;
        /* Wait for last operation to be completed */
        status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);
        if (status_value == FLASH_EOP)
        {
            /* Clears the FLASH's pending flags */
            FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);

            /* if the erase operation is completed, disable the OPTER Bit */
            FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            /* Enable the Option Bytes Programming operation */
            FLASH->CTRL |= FLASH_CTRL_SET_OPTPG;

            OBT->USER_RDP = user_temp;
            /* Wait for last operation to be completed */
            status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);

            if (status_value == FLASH_EOP)
            {
                /* Clears the FLASH's pending flags */
                FLASH_Flag_Status_Clear(FLASH_STS_CLRFLAG);

                /* Enables the read out protection L2 */
                OBT->USER4_RDP2 = FLASH_L2_RDP_KEY;

                /* Wait for last operation to be completed */
                status_value = FLASH_Last_Operation_Wait(ERASE_TIMEOUT);
            }
            else
            {
                /*No process*/
            }

            if (status_value != FLASH_TIMEOUT)
            {
                /* if the program operation is completed, disable the OPTPG Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTPG;
            }
            else
            {
                /*No process*/
            }
        }
        else
        {
            if (status_value != FLASH_TIMEOUT)
            {
                /* Disable the OPTER Bit */
                FLASH->CTRL &= FLASH_CTRL_RESET_OPTER;
            }
            else
            {
                /*No process*/
            }
        }
    }
    else
    {
        /*No process*/
    }
    /* Return the protection operation status_value */
    return status_value;
}

/**
 *\*\name   FLASH_Option_Bytes_User_Get
 *\*\fun    Returns the FLASH User Option Bytes values.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_bit
 *\*\            - FLASH_OB_IWDG_SW
 *\*\            - FLASH_OB_STOP_NORST
 *\*\            - FLASH_OB_PD_NORST
 *\*\            - FLASH_OB_NOLOCK_BOOT
 *\*\            - FLASH_OB_PA0_NRST
 *\*\return FlagStatus :
 *\*\            - SET
 *\*\            - RESET
 **/
FlagStatus FLASH_Option_Bytes_User_Get(uint32_t option_byte_bit)
{
    if (((FLASH->OB >> FLASH_OB_OFFSET) & option_byte_bit) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Option_Bytes_User2_Get
 *\*\fun    Returns the FLASH Option Bytes LVRCNT values.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return LVRCNT:
 *\*\            - 0x00 to 0xFF.
 **/
uint32_t FLASH_Option_Bytes_User2_Get(void)
{
    /* Return the User Option Byte2 */
    return (uint32_t)(FLASH->USER & FLASH_USER_LVRCNT_MSK);
}

/**
 *\*\name   FLASH_User_LVRLS_Get
 *\*\fun    Returns the FLASH Option Bytes LVRLS values.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return LVRLS:
 *\*\            - 0x00 to 0x0F.
 **/
uint32_t FLASH_User_LVRLS_Get(void)
{
    /* Return the Option Byte User3 LVRLS */
    return (uint32_t)((FLASH->USER & FLASH_USER_LVRLS_MSK) >> FLASH_USER3_OFFSET);
}

/**
 *\*\name   FLASH_Option_Bytes_User3_Get
 *\*\fun    Returns the FLASH Option Bytes User3 values.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  option_byte_bit
 *\*\            - FLASH_OB_USER_LVR_ENABLE
 *\*\            - FLASH_OB_USER_LVRFIL_ENABLE
 *\*\return FlagStatus :
 *\*\            - SET
 *\*\            - RESET
 **/
FlagStatus FLASH_Option_Bytes_User3_Get(uint32_t option_byte_bit)
{
    if (((FLASH->USER >> FLASH_USER3_OFFSET) & option_byte_bit) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Option_Bytes_User4_Get
 *\*\fun    Returns the FLASH Option Bytes LVRCNT values.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return LVRCNT:
 *\*\            - 0x00 to 0xFF.
 **/
uint32_t FLASH_Option_Bytes_User4_Get(void)
{
    /* Return the Option Byte User4 */
    return (uint32_t)((FLASH->USER & FLASH_USER_POR_DELAY_MSK) >> FLASH_USER4_OFFSET);
}

/**
 *\*\name   FLASH_Read_Out_Protection_Status_Get
 *\*\fun    Checks whether the FLASH Read Out Protection status_value is set or not.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FlagStatus :
 *\*\        - SET
 *\*\        - RESET
 **/
FlagStatus FLASH_Read_Out_Protection_Status_Get(void)
{
    if ((FLASH->OB & FLASH_RDPRTL1_MSK) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Read_Out_Protection_L2_Status_Get
 *\*\fun    Checks whether the FLASH Read Out Protection L2 status_value is set or not.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FlagStatus :
 *\*\        - SET
 *\*\        - RESET
 **/
FlagStatus FLASH_Read_Out_Protection_L2_Status_Get(void)
{
    if ((FLASH->OB & FLASH_RDPRTL2_MSK) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Prefetch_Buffer_Status_Get
 *\*\fun    Checks whether the FLASH Prefetch Buffer status_value is set or not.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FlagStatus :
 *\*\        - SET
 *\*\        - RESET
 **/
FlagStatus FLASH_Prefetch_Buffer_Status_Get(void)
{
    if ((FLASH->AC & FLASH_PRFTBS_MSK) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Interrupt_Enable
 *\*\fun    Enables the specified FLASH interrupts.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  flash_interrupts :
 *\*\        - FLASH_INT_ERROR    FLASH Error Interrupt
 *\*\        - FLASH_INT_EOP      FLASH end of operation Interrupt
 *\*\return none
 **/
void FLASH_Interrupt_Enable(uint32_t flash_interrupts)
{

    /* Enable the interrupt sources */
    FLASH->CTRL |= flash_interrupts;
}

/**
 *\*\name   FLASH_Interrupt_Disable
 *\*\fun    Disables the specified FLASH interrupts.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  flash_interrupts :
 *\*\        - FLASH_INT_ERROR    FLASH Error Interrupt
 *\*\        - FLASH_INT_EOP      FLASH end of operation Interrupt
 *\*\return none
 **/
void FLASH_Interrupt_Disable(uint32_t flash_interrupts)
{
    /* Disable the interrupt sources */
    FLASH->CTRL &= ~(uint32_t)flash_interrupts;
}

/**
 *\*\name   FLASH_Flag_Status_Get
 *\*\fun    Checks whether the specified FLASH flag is set or not.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  flash_flag :
 *\*\        - FLASH_FLAG_BUSY      FLASH Busy flag
 *\*\        - FLASH_FLAG_PGERR     FLASH Program error flag
 *\*\        - FLASH_FLAG_WRPERR    FLASH Write protected error flag
 *\*\        - FLASH_FLAG_EOP       FLASH End of Operation flag
 *\*\return FlagStatus :
 *\*\        - SET
 *\*\        - RESET
 **/
FlagStatus FLASH_Flag_Status_Get(uint32_t flash_flag)
{
    if ((FLASH->STS & flash_flag) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Option_Bytes_Flag_Get
 *\*\fun    Checks whether the specified FLASH flag is set or not.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  flash_flag :
 *\*\        - FLASH_FLAG_OBERR FLASH Option Byte error flag
 *\*\return FlagStatus :
 *\*\        - SET
 *\*\        - RESET
 **/
FlagStatus FLASH_Option_Bytes_Flag_Get(uint32_t flash_flag)
{
    if ((FLASH->OB & flash_flag) != (uint32_t)RESET)
    {
        return SET;
    }
    else
    {
        return RESET;
    }
}

/**
 *\*\name   FLASH_Flag_Status_Clear
 *\*\fun    Clears the FLASH's status flags.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  flash_flag :
 *\*\        - FLASH_FLAG_PGERR     FLASH Program error flag
 *\*\        - FLASH_FLAG_WRPERR    FLASH Write protected error flag
 *\*\        - FLASH_FLAG_EOP       FLASH End of Operation flag
 *\*\return none
 **/
void FLASH_Flag_Status_Clear(uint32_t flash_flag)
{
    /* Clear the flags */
    FLASH->STS |= flash_flag;
}

/**
 *\*\name   FLASH_Status_Get
 *\*\fun    Returns the FLASH_STS.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  none
 *\*\return FLASH_STS :
 *\*\        - FLASH_BUSY
 *\*\        - FLASH_ERR_PG
 *\*\        - FLASH_ERR_WRP
 *\*\        - FLASH_EOP
 **/
FLASH_STS FLASH_Status_Get(void)
{
    FLASH_STS status_value = FLASH_EOP;

    if ((FLASH->STS & FLASH_FLAG_BUSY) == FLASH_FLAG_BUSY)
    {
        status_value = FLASH_BUSY;
    }
    else
    {
        if ((FLASH->STS & FLASH_FLAG_PGERR) != RESET)
        {
            status_value = FLASH_ERR_PG;
        }
        else
        {
            if ((FLASH->STS & FLASH_FLAG_WRPERR) != RESET)
            {
                status_value = FLASH_ERR_WRP;
            }
            else
            {
                status_value = FLASH_EOP;
            }
        }
    }

    /* Return the FLASH_STS */
    return status_value;
}

/**
 *\*\name   FLASH_Last_Operation_Wait
 *\*\fun    Waits for a Flash operation to complete or a timeout to occur.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  timeout :
 *\*\            - ERASE_TIMEOUT
 *\*\            - PROGRAM_TIMEOUT
 *\*\return FLASH_STS: The returned value can be:
 *\*\            - FLASH_BUSY
 *\*\            - FLASH_ERR_PG
 *\*\            - FLASH_ERR_WRP
 *\*\            - FLASH_EOP
 *\*\            - FLASH_TIMEOUT
 **/
FLASH_STS FLASH_Last_Operation_Wait(uint32_t timeout)
{
    FLASH_STS status_value = FLASH_EOP;

    /* Check for the Flash status_value */
    status_value = FLASH_Status_Get();
    /* Wait for a Flash operation to complete or a timeout to occur */
    while ((status_value == FLASH_BUSY) && (timeout != 0x00))
    {
        status_value = FLASH_Status_Get();
        timeout--;
    }
    if (timeout == 0x00)
    {
        status_value = FLASH_TIMEOUT;
    }
    /* Return the operation status_value */
    return status_value;
}

/**
 *\*\name   FLASH_VTOR_Address_Set
 *\*\fun    Set interrupt vector offset address.
 *\*\note   This function can be used for N32G003 devices.
 *\*\param  VTOR_address :
 *\*\            - 0x00000000~0x7FFFFFFF
 *\*\param  VTOR_cmd :
 *\*\            - FLASH_VTOR_ENABLE
 *\*\            - FLASH_VTOR_DISABLE
 *\*\return none
 **/
void FLASH_VTOR_Address_Set(uint32_t VTOR_address, uint32_t VTOR_cmd)
{
    /* Set VTOR address */
    FLASH->VTOR = (VTOR_cmd | VTOR_address);
}
