/* USER CODE BEGIN Header */
/* you can remove the copyright */

/*
 * Copyright 2020-2025 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * @file main.c
 * @brief Fls_Demo with Button-driven JTAG lock/unlock via CUS_NVR
 *
*/

/* USER CODE END Header */
#include "Mcal.h"
/* Includes ------------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Fls_Nvr.h"
#include "IntCtrl_Lld.h"
#include "IntCtrl_Lld_Cfg.h"
#include "pSIP_Efm.h"
#include "pSIP_Gpio.h"
#include "pSIP_Pctrl.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define EFM_DEBUGGER_TAG_OFFSET     (0x08U)         /* JTAG tag offset inside CUS_NVR */
#define EFM_DEBUGGER_TAG_ENABLE     (0xFFFFFFFFU)   /* Value to enable JTAG/SWD */
#define EFM_DEBUGGER_TAG_DISABLE    (0x5A5A5A5AU)   /* Value to disable JTAG/SWD */
#define CUS_NVR_CUSTOMER_KEY        (0x4DFF32U)     /* Default CUS_NVR unlock key */

#define BTN_SW1_PIN                 (0U)            /* PE0 - SW1 enables JTAG  */
#define BTN_SW2_PIN                 (1U)            /* PE1 - SW2 disables JTAG */
#define BTN_PCR_IRQC_FALLING_EDGE   (0xAU)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint8 g_sw1_pressed = 0U;
volatile uint8 g_sw2_pressed = 0U;
/* USER CODE END PV */

/* Private function declare --------------------------------------------------*/
/* USER CODE BEGIN PFDC */
static void Btn_Init(void);
static Fls_Lld_ReturnType Jtag_UpdateTag(uint32 tagValue, uint8 *cusNvrBuf);
/* USER CODE END PFDC */
static void Board_Init(void);

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void GPIOE_IRQHandler(void)
{
    uint32 flags = GPIOE->PIFR;

    if (0U != (flags & (1U << BTN_SW1_PIN)))
    {
        GPIOE->PIFR = (1U << BTN_SW1_PIN);  /* W1C clear */
        g_sw1_pressed = 1U;
    }

    if (0U != (flags & (1U << BTN_SW2_PIN)))
    {
        GPIOE->PIFR = (1U << BTN_SW2_PIN);
        g_sw2_pressed = 1U;
    }
}

static void Btn_Init(void)
{
    /* Route PE0/PE1 to GPIO function (PCTRL_MUX_AS_GPIO = 1) */
    PCTRLE->PCR[BTN_SW1_PIN] = PCTRL_PCR_MUX(1U);
    PCTRLE->PCR[BTN_SW2_PIN] = PCTRL_PCR_MUX(1U);

    /* Configure falling-edge interrupt in GPIO PCR */
    GPIOE->PCR[BTN_SW1_PIN] = GPIO_PCR_IRQC(BTN_PCR_IRQC_FALLING_EDGE);
    GPIOE->PCR[BTN_SW2_PIN] = GPIO_PCR_IRQC(BTN_PCR_IRQC_FALLING_EDGE);

    /* Clear any pending flags */
    GPIOE->PIFR = (1U << BTN_SW1_PIN) | (1U << BTN_SW2_PIN);

    /* Enable input on both pins */
    GPIOE->PIER |= (1U << BTN_SW1_PIN) | (1U << BTN_SW2_PIN);
}

static Fls_Lld_ReturnType Jtag_UpdateTag(uint32 tagValue, uint8 *cusNvrBuf)
{
    Fls_Lld_ReturnType status;

    /* 1. Read full CUS_NVR sector so other fields are preserved */
    status = Fls_ReadCusNvr(FLS_CUS_NVR_BASE_ADDR, cusNvrBuf,
                            FLS_CUS_NVR_LENGTH, CUS_NVR_CUSTOMER_KEY);
    if (FLASH_E_OK != status)
    {
        return status;
    }

    /* 2. Patch JTAG tag at offset 0x08 */
    *((volatile uint32 *)(cusNvrBuf + EFM_DEBUGGER_TAG_OFFSET)) = tagValue;

    /* 3. Erase the CUS_NVR sector */
    status = Fls_EraseCusNvr(CUS_NVR_CUSTOMER_KEY);
    if (FLASH_E_OK != status)
    {
        return status;
    }

    /* 4. Write the whole sector back */
    status = Fls_WriteCusNvr(FLS_CUS_NVR_BASE_ADDR, cusNvrBuf,
                             FLS_CUS_NVR_LENGTH, CUS_NVR_CUSTOMER_KEY);
    return status;
}
/* USER CODE END 0 */


/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
    /* USER CODE BEGIN 1 */
    uint8 cus_nvr_buf[FLS_CUS_NVR_LENGTH] = {0};
    Fls_Lld_ReturnType nvrStatus;

    Mcu_Init(&Mcu_Config);
    Mcu_InitClock(0);
#if (MCU_NO_PLL == STD_OFF)
    while (MCU_PLL_LOCKED != Mcu_GetPllStatus())
    {
        /* Wait until PLL is locked */
    }
    Mcu_DistributePllClock();
#endif
    /* USER CODE END 1 */ 
    Board_Init();
    /* USER CODE BEGIN 2 */
    /* Snapshot current CUS_NVR for in-place editing */
    nvrStatus = Fls_ReadCusNvr(FLS_CUS_NVR_BASE_ADDR, cus_nvr_buf,
                               FLS_CUS_NVR_LENGTH, CUS_NVR_CUSTOMER_KEY);
    if (FLASH_E_OK != nvrStatus)
    {
        while (1)
        {
            /* Halt on read failure */
        }
    }
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */
        /* USER CODE BEGIN 3 */
        if (0U != g_sw1_pressed)
        {
            g_sw1_pressed = 0U;
            nvrStatus = Jtag_UpdateTag(EFM_DEBUGGER_TAG_ENABLE, cus_nvr_buf);
            if (FLASH_E_OK == nvrStatus)
            {
                Mcu_Lld_SystemReset();
            }
        }

        if (0U != g_sw2_pressed)
        {
            g_sw2_pressed = 0U;
            nvrStatus = Jtag_UpdateTag(EFM_DEBUGGER_TAG_DISABLE, cus_nvr_buf);
            if (FLASH_E_OK == nvrStatus)
            {
                Mcu_Lld_SystemReset();
            }
        }
    }
    /* USER CODE END 3 */
}

static void Board_Init(void)
{
    Port_Init(&Port_Config);
    (void)IntCtrl_Lld_Init(&IntCtrlConfig);
    Fls_Init(&Fls_Config);
    Btn_Init();
}

/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
