/*!
 * @file        apm32f445_446_rtc.c
 *
 * @brief       This file provides all the RTC firmware functions
 *
 * @version     V1.0.0
 *
 * @date        2026-01-31
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful 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 SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "apm32f445_446_rtc.h"

/** @addtogroup APM32F445_446_StdPeriphDriver
  @{
*/

/** @addtogroup RTC_Driver RTC Driver
  @{
*/

/** @defgroup RTC_Marcos Marcos
  @{
*/

/*******************************************************************************
 *                              ENUMS
 ******************************************************************************/

/* Number of instances of the RTC module */
#define RTC_INSTANCE_COUNT   (1u)
#define ASSERT_INSTANCE(__ins__) ({if(__ins__ >= RTC_INSTANCE_COUNT) {while(1);}})

/**@} end of group RTC_Marcos*/

/** @defgroup RTC_Structures Structures
  @{
*/

/*******************************************************************************
 *                              STRUCTS
 ******************************************************************************/

/*!
 * @brief static RTC runtime structure.
 */
static struct
{
    RTC_ALARM_CONFIG_T        *alarmConfig;      /* Alarm configuration                  */
    bool                       isAlarmTimeNew;   /* Check if there is a new alarm        */
    RTC_INTERRUPT_CONFIG_T    *intConfig;        /* Interrupt configuration              */
    RTC_SECONDS_INT_CONFIG_T  *secondsIntConfig; /* Time seconds interrupt configuration */
} G_RTCRUNTIMECONFIG[RTC_INSTANCE_COUNT];

/**@} end of group RTC_Structures*/

/** @defgroup RTC_Variables Variables
  @{
*/

/*******************************************************************************
 *                              GLOBAL VARIABLES
 ******************************************************************************/

/* Table of RTC base pointers */
static RTC_T *const g_rtcBasePointer[RTC_INSTANCE_COUNT] = { RTC };

/* @brief Table used to store the RTC IRQ names */
static const IRQn_Type g_rtcIrqNumbers[] = { RTC_IRQn };
/* @brief Table used to store the RTC Seconds IRQ names */
static const IRQn_Type g_rtcSecondsIrqNb[] = { RTC_Seconds_IRQn };

/* Table of month length (in days) for the Un-leap-year */
static const uint8_t g_MonthLengthInULY[] =
{0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};

/* Table of month length (in days) for the Leap-year */
static const uint8_t g_MonthLengthInLY[] =
{0U, 31U, 29U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};

/* Number of days from begin of the non Leap-year */
static const uint16_t g_MonthDays[] =
{0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};

/**@} end of group RTC_Variables*/

/** @defgroup RTC_Functions Functions
  @{
*/

/*******************************************************************************
 *                      PRIVATE FUNCTION DECLARATIONS
 ******************************************************************************/

static bool RTC_RegisterLockedVerify(const RTC_T *const rtcBase, RTC_LOCK_REG_SEL_T regLockSelect);

/*******************************************************************************
 *                          PUBLIC DRIVER FUNCTIONS
 ******************************************************************************/

/*!
 * @brief This function deinitializes the RTC instance.
 *
 * @param ins: The number of the RTC instance used
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if Control register is locked.
 */
STATUS_T RTC_DeInit(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;

    /* Check if the control register is locked.
     * If true, the method cannot continue.
     */
    if (!RTC_RegisterLockedVerify(g_rtcBasePointer[ins], RTC_LOCK_REG_CTRL))
    {
        /* Disable RTC instance's interrupts */
        INT_SYS_DisableIRQ(g_rtcIrqNumbers[ins]);
        INT_SYS_DisableIRQ(g_rtcSecondsIrqNb[ins]);
        /* Perform a software reset */
        RTC_HW_SoftwareReset(g_rtcBasePointer[ins]);
        /* Clear the pending interrupt generated by the software reset */
        INT_SYS_ClearPending(g_rtcIrqNumbers[ins]);
    }
    else
    {
        status = STATUS_ERROR;
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief This function will set the default configuration
 *        values into the structure passed as a parameter.
 *
 * @param rtcInitConfig: Pointer to the structure in which the
 *                       configuration will be saved.
 *
 * @retval None
 */
void RTC_DefaultConfig(RTC_INIT_CONFIG_T *const rtcInitConfig)
{
    rtcInitConfig->clockSelect               = RTC_CLK_SRC_OSC_32KHZ;
    rtcInitConfig->clockOutConfig            = RTC_CLKOUT_DISABLED;
    rtcInitConfig->updateEnable              = true;
    rtcInitConfig->nonSupervisorAccessEnable = true;
    rtcInitConfig->compensation              = 0;
    rtcInitConfig->compensationInterval      = 0U;
}

/*!
 * @brief This function initializes the RTC instance with the settings
 *        provided by the user via the rtcInitConfig parameter.
 *
 * @param ins: The number of the RTC instance used
 * @param rtcInitConfig: Pointer to the user's configuration structure
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if Control is locked.
 */
STATUS_T RTC_Init(uint32_t ins, const RTC_INIT_CONFIG_T *const rtcInitConfig)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;
    RTC_T *basePtr = g_rtcBasePointer[ins];

    /* Initialize runtime structure */
    G_RTCRUNTIMECONFIG[ins].alarmConfig      = NULL;
    G_RTCRUNTIMECONFIG[ins].intConfig        = NULL;
    G_RTCRUNTIMECONFIG[ins].secondsIntConfig = NULL;
    G_RTCRUNTIMECONFIG[ins].isAlarmTimeNew   = false;

    /* Check if the control register is locked.
     * If true, the method cannot continue.
     */
    if (!RTC_RegisterLockedVerify(basePtr, RTC_LOCK_REG_CTRL))
    {
        /* Disable the RTC instance IRQ to perform a software reset */
        INT_SYS_DisableIRQ(g_rtcIrqNumbers[ins]);
        /* Perform a software reset */
        RTC_HW_SoftwareReset(basePtr);
        /* Set seconds register to 1 to clear TIF flag and stop generating interrupts */
        status = RTC_HW_AssignTimeSecondsRegister(basePtr, 1U);
        /* Clear the pending interrupt generated by the software reset */
        INT_SYS_ClearPending(g_rtcIrqNumbers[ins]);
        /* Setup the RTC instance as configured in the structure */
        (void)RTC_ConfigClockOut(basePtr, rtcInitConfig->clockOutConfig);
        RTC_HW_PickLPOSelect(basePtr, rtcInitConfig->clockSelect);
        RTC_HW_PickUpdateMode(basePtr, rtcInitConfig->updateEnable);
        RTC_HW_PickNonSupervisorAccess(basePtr, rtcInitConfig->nonSupervisorAccessEnable);
        /* Check if compensation needs to be updated */
        if (rtcInitConfig->compensation != 0)
        {
            RTC_HW_AssignTimeCompensation(basePtr,
                                          rtcInitConfig->compensation,
                                          rtcInitConfig->compensationInterval);
        }
    }
    else
    {
        status = STATUS_ERROR;
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Start RTC instance counter.
 *
 * @param ins: The number of the RTC instance used
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the counter cannot be enabled or is already enabled.
 */
STATUS_T RTC_StartCounter(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;

    /* Check if the TCE is writable and return corresponding status */
    if (RTC_CanWriteTCE(ins) == false)
    {
        status = STATUS_ERROR;
    }
    else
    {
        /* Enable the counter */
        status = RTC_HW_Enable(g_rtcBasePointer[ins]);
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Stop RTC instance counter
 *
 * @param ins: The number of the RTC instance used
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the counter could not be stopped.
 */
STATUS_T RTC_StopCounter(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;

    /* Check if the TCE is writable */
    if (RTC_CanWriteTCE(ins) == false)
    {
        status = STATUS_ERROR;
    }
    else
    {
        /* Disable the RTC instance */
        status = RTC_HW_Disable(g_rtcBasePointer[ins]);
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief This method configures time compensation.
 *
 * @param ins: The number of the RTC instance used
 * @param compInterval: Compensation interval
 * @param compensation: Compensation value
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the TC Register is locked.
 */
STATUS_T RTC_ConfigTimeCompensation(uint32_t ins, uint8_t compInterval, int8_t compensation)
{
    ASSERT_INSTANCE(ins);

    /* Declare local variables */
    STATUS_T status = STATUS_SUCCESS;

    /* Check if the TCR is not locked */
    if (RTC_RegisterLockedVerify(g_rtcBasePointer[ins], RTC_LOCK_REG_TCL) == false)
    {
        /* Set the corresponding values for compensation and compensation interval */
        RTC_HW_AssignTimeCompensation(g_rtcBasePointer[ins], compensation, compInterval);
    }
    else
    {
        /* Set the exit code to locked */
        status = STATUS_ERROR;
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief This retrieves the time compensation coefficients and saves
 *        them on the variables referenced by the parameters.
 *
 * @param ins: The number of the RTC instance used
 * @param compInterval: Pointer to the variable in which to
 *                      save the compensation interval
 * @param compensation: Pointer to the variable in which to
 *                      save the compensation value
 *
 * @retval None
 *
 * @note all the registers are unlocked
 *       only by software reset or power on reset.
 *       (Except for CR that is unlocked only by power on reset).
 */
void RTC_ReadTimeCompensation(uint32_t ins, uint8_t *compInterval, int8_t *compensation)
{
    ASSERT_INSTANCE(ins);

    /* Get the compensation interval */
    RTC_HW_ReadCurrentTimeCompensation(g_rtcBasePointer[ins], compensation, compInterval);
}

/*!
 * @brief This function checks the following conditions to find if the
 *        time counter enable bit is writable.
 *
 * @param ins: The number of the RTC instance used
 *
 * @retval True if the TCE can be set, otherwise false
 */
bool RTC_CanWriteTCE(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    bool result = true;
    bool isTimeInvalidEnable = false;
    bool isTimeOverEnable = false;
    bool isTimeCountEnable = false;

    /* Check if the status register is locked */
    if (RTC_RegisterLockedVerify(g_rtcBasePointer[ins], RTC_LOCK_REG_STATUS) == false)
    {
        result = true;
    }
    /* Get the update mode bit */
    else if (RTC_HW_ReadUpdateMode(g_rtcBasePointer[ins]))
    {
        isTimeInvalidEnable = RTC_HW_ReadTimeInvalidFlag(g_rtcBasePointer[ins]);
        isTimeOverEnable = RTC_HW_ReadTimeOverflowFlag(g_rtcBasePointer[ins]);
        isTimeCountEnable = RTC_HW_ReadTimeCounterState(g_rtcBasePointer[ins]);

        /* Check for the specified conditions */
        if ((isTimeInvalidEnable == false) && (isTimeOverEnable == false) && (isTimeCountEnable == true))
        {
            result = false;
        }
    }
    else
    {
        result = false;
    }

    /* Return the exit code */
    return result;
}

/*!
 * @brief Assign time and date for RTC instance.
 *
 * @param ins: The number of the RTC instance used
 * @param timeDate: Pointer to the variable in which the time is stored
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the time provided was invalid or
 *         if the counter was not stopped.
 *
 * @note The user must stop the counter before using this function.
 *       Otherwise it will return an error
 */
STATUS_T RTC_AssignTimeDate(uint32_t ins, const RTC_TIMEDATE_T *const timeDate)
{
    ASSERT_INSTANCE(ins);

    /* Declare local variables */
    STATUS_T status = STATUS_SUCCESS;
    uint32_t seconds = 0;

    /* Check if the time is in the correct format */
    if (RTC_TimeDateCorrectFormatVerify(timeDate) == false)
    {
        /* Set the exit code to error */
        status = STATUS_ERROR;
    }
    /* Check if the TCE bit is writable */
    else if (RTC_CanWriteTCE(ins) == false)
    {
        /* Set the exit code to locked */
        status = STATUS_ERROR;
    }
    else
    {
        /* Convert the desired time to seconds */
        RTC_ConvertTimeDateToSeconds(timeDate, &seconds);
        /* Set the time */
        status = RTC_HW_AssignTimeSecondsRegister(g_rtcBasePointer[ins], seconds);
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Read current time and date from RTC instance
 *
 * @param ins: The number of the RTC instance used
 * @param currentTime: Pointer to the variable in which to store the result
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if there was a problem.
 */
STATUS_T RTC_ReadCurrentTimeDate(uint32_t ins, RTC_TIMEDATE_T *const currentTime)
{
    ASSERT_INSTANCE(ins);

    /* Declare local variables */
    STATUS_T status = STATUS_SUCCESS;
    uint32_t seconds = 0;
    uint32_t seconds_temp = 0;

    /* Make two consecutive reads to ensure that the read was not
     * done when the counter is incrementing.
     * This is recommended in the reference manual.
     */
    seconds_temp = RTC_HW_ReadTimeSecondsRegister(g_rtcBasePointer[ins]);
    seconds = RTC_HW_ReadTimeSecondsRegister(g_rtcBasePointer[ins]);
    /* If the read was done when the counter was incrementing,
     * try and read again.
     */
    if (seconds_temp == seconds)
    {
        /* Convert the current time from seconds to time date structure */
        RTC_ConvertSecondsToTimeDate(&seconds, currentTime);
    }
    else
    {
        /* Reinitialize the temporary variable */
        seconds_temp = 0UL;
        /* Get the current time again */
        seconds_temp = RTC_HW_ReadTimeSecondsRegister(g_rtcBasePointer[ins]);
        if (seconds_temp == seconds)
        {
            /* Convert the current time from seconds to time date structure */
            RTC_ConvertSecondsToTimeDate(&seconds, currentTime);
        }
        else
        {
            /* If the last two reads are not equal, there is an error */
            status = STATUS_ERROR;
        }
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Verify if the date time struct is configured properly
 *
 * @param timeDate: Structure to check to check
 *
 * @retval True if the time date is in the correct format, false if not
 */
bool RTC_TimeDateCorrectFormatVerify(const RTC_TIMEDATE_T *const timeDate)
{
    /* Declare local variables */
    bool returnCode = true;
    /* Set the days-in-month table for the corresponding year */
    const uint8_t *pDays = RTC_YearLeapVerify(timeDate->year) ?
                             (g_MonthLengthInLY) : (g_MonthLengthInULY);

    /* Check if the day is a valid day from the corresponding month */
    if (timeDate->day > pDays[timeDate->month])
    {
        returnCode = false;
    }
    /* Check if the time and date are in the correct ranges */
    else if ((timeDate->seconds >= SECONDS_IN_A_MIN) ||
            (timeDate->minutes >= MINS_IN_A_HOUR) ||
            (timeDate->hour >= HOURS_IN_A_DAY) ||
            (timeDate->day < 1U) ||
            (timeDate->day > 31U) ||
            (timeDate->month < 1U) ||
            (timeDate->month > 12U) ||
            (timeDate->year < YEAR_RANGE_START) ||
            (timeDate->year > YEAR_RANGE_END))
    {
        returnCode = false;
    }
    else
    {
        returnCode = true;
    }

    /* Return the exit code */
    return returnCode;
}

/*!
 * @brief Verify if the current year is leap
 *
 * @param year: Year to check
 *
 * @retval True if the year is leap, false if not
 */
bool RTC_YearLeapVerify(uint16_t year)
{
    bool isYearLeap = false;

    if(((year % 4) == 0) && (((year % 400) == 0) || ((year % 100) != 0)))
    {
        isYearLeap = true;
    }
    else
    {
        isYearLeap = false;
    }

    /* Return the exit code */
    return isYearLeap;
}

/*!
 * @brief Convert seconds to RTC_TIMEDATE_T structure
 *
 * @param seconds: Pointer to the seconds
 * @param timeDate: Pointer to the structure in which to store the result
 *
 * @retval None
 */
void RTC_ConvertSecondsToTimeDate(const uint32_t *const seconds, RTC_TIMEDATE_T *const timeDate)
{
    /* Declare the variables needed */
    uint8_t i = 0U;
    bool yearLeap = false;
    uint32_t numberOfDays = 0U;
    uint32_t seconds_temp = 0U;
    uint16_t daysInYear = 0U;

    /* Because the starting year(1970) is not leap, set the daysInYear
     * variable with the number of the days in a normal year
     */
    daysInYear = DAYS_IN_A_YEAR;

    /* Set the year to the beginning of the range */
    timeDate->year = YEAR_RANGE_START;

    /* Get the number of days */
    numberOfDays = (*seconds) / SECONDS_IN_A_DAY;
    /* Get the number of seconds remaining */
    seconds_temp = (*seconds) % SECONDS_IN_A_DAY;

    /* Get the current hour */
    timeDate->hour = (uint16_t)(seconds_temp / SECONDS_IN_A_HOUR);
    /* Get the remaining seconds */
    seconds_temp = seconds_temp % SECONDS_IN_A_HOUR;
    /* Get the minutes */
    timeDate->minutes = (uint16_t)(seconds_temp / SECONDS_IN_A_MIN);
    /* Get seconds */
    timeDate->seconds = (uint8_t)(seconds_temp % SECONDS_IN_A_MIN);

    /* Get the current year */
    while (numberOfDays >= daysInYear)
    {
        /* Increment year if the number of days is greater than the ones in
         * one year
         */
        timeDate->year++;
        /* Subtract the number of the days */
        numberOfDays -= daysInYear;

        /* Check if the year is leap or unleap */
        if (!RTC_YearLeapVerify(timeDate->year))
        {
            /* Set the number of non leap year to the current year number
             * of days.
             */
            daysInYear = DAYS_IN_A_YEAR;
        }
        else
        {
            /* Set the number of leap year to the current year number
             * of days.
             */
            daysInYear = DAYS_IN_A_LEAP_YEAR;
        }
    }

    /* Add the current day */
    numberOfDays += 1U;

    /* Check if the current year is leap */
    yearLeap = RTC_YearLeapVerify(timeDate->year);

    /* Get the month */
    for (i = 1U; i <= 12U; i++)
    {
        uint32_t daysInCurrentMonth = ((yearLeap != true) ?
          (uint32_t)g_MonthLengthInULY[i] : (uint32_t)g_MonthLengthInLY[i]);
        if (numberOfDays > daysInCurrentMonth)
        {
            numberOfDays -= daysInCurrentMonth;
        }
        else
        {
            timeDate->month = (uint16_t)i;
            break;
        }

    }

    /* Set the current day */
    timeDate->day = (uint16_t)numberOfDays;
}

/*!
 * @brief Convert seconds to RTC_TIMEDATE_T structure
 *
 * @param timeDate: Pointer to the source struct
 * @param seconds: Pointer to the variable in which to store the result
 *
 * @retval None
 */
void RTC_ConvertTimeDateToSeconds(const RTC_TIMEDATE_T *const timeDate, uint32_t *const seconds)
{
    /* Declare local variables */
    uint16_t year;

    /* Convert years to seconds */
    (*seconds) = (uint32_t)(DAYS_IN_A_YEAR * (uint32_t)(SECONDS_IN_A_DAY));
    (*seconds) *= ((uint32_t)timeDate->year - YEAR_RANGE_START);

    /* Add the seconds from the leap years */
    for (year = YEAR_RANGE_START; year < timeDate->year; year++)
    {
        if (RTC_YearLeapVerify(year))
        {
            (*seconds) += SECONDS_IN_A_DAY;
        }
    }

    /* If the current year is leap and 29th of February has passed, add
     * another day to seconds passed.
     */
    if ((RTC_YearLeapVerify(year)) && (timeDate->month > 2U))
    {
        (*seconds) += SECONDS_IN_A_DAY;
    }

    /* Add the rest of the seconds from the current month */
    (*seconds) += g_MonthDays[timeDate->month] * SECONDS_IN_A_DAY;
    /* Add the rest of the seconds from the current day */
    (*seconds) += (uint32_t)(((uint32_t)timeDate->day - 1U) * (uint32_t)SECONDS_IN_A_DAY);
    /* Add the rest of the seconds from the current time */
    (*seconds) += (uint32_t)(((uint32_t)timeDate->hour * SECONDS_IN_A_HOUR)   + \
                             ((uint32_t)timeDate->minutes * SECONDS_IN_A_MIN) + \
                             (uint32_t)timeDate->seconds);
}

/*!
 * @brief This method configures the alarm with the
 *        configuration from the alarmConfig parameter.
 *
 * @param ins: The number of the RTC instance used
 * @param alarmConfig: Pointer to the structure which holds the alarm configuration
 *
 * @retval STATUS_SUCCESS if the configuration is successful,
 *         STATUS_ERROR if the alarm time is invalid.
 */
STATUS_T RTC_AlarmConfig(uint32_t ins, RTC_ALARM_CONFIG_T *const alarmConfig)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;
    uint32_t alarmTime = 0;
    uint32_t currentTime = 0;

    /* Check if the alarm time is in a correct format */
    if (RTC_TimeDateCorrectFormatVerify(&(alarmConfig->alarmTime)) == true)
    {
        /* Convert the time date to seconds */
        RTC_ConvertTimeDateToSeconds(&(alarmConfig->alarmTime), &alarmTime);
        /* Get current time in seconds */
        currentTime = RTC_HW_ReadTimeSecondsRegister(g_rtcBasePointer[ins]);

        /* Check if the alarm time is greater than current time */
        if(alarmTime > currentTime)
        {
            /* Disable the IRQ to avoid accidental interrupt requests */
            INT_SYS_DisableIRQ(g_rtcIrqNumbers[ins]);
            G_RTCRUNTIMECONFIG[ins].alarmConfig = alarmConfig;

            /* Write alarm time into Time Alarm Register */
            RTC_HW_AssignTimeAlarmRegister(g_rtcBasePointer[ins], alarmTime);
            /* Enable/disable interrupt source based on the configuration */
            RTC_HW_ConfigTimeAlarmIntEnable(g_rtcBasePointer[ins], alarmConfig->alarmIntEnable);
            /* After the configuration is done, re-enable the interrupt in
             * NVIC.
             */
            INT_SYS_EnableIRQ(g_rtcIrqNumbers[ins]);
        }
        else
        {
            status = STATUS_ERROR;
        }
    }
    else
    {
        status = STATUS_ERROR;
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Read alarm configuration for RTC instance
 *
 * @param ins: The number of the RTC instance used
 * @param alarmConfig: Pointer to the structure in which to
 *                     store the alarm configuration
 *
 * @retval None
 */
void RTC_ReadAlarmConfig(uint32_t ins, RTC_ALARM_CONFIG_T *alarmConfig)
{
    ASSERT_INSTANCE(ins);

    *alarmConfig = *(G_RTCRUNTIMECONFIG[ins].alarmConfig);
}

/*!
 * @brief Verify if alarm is pending
 *
 * @param ins: The number of the RTC instance used
 *
 * @retval True if the alarm has occurred, false if not
 */
bool RTC_AlarmPendingVerify(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    /* Return the exit code */
    return RTC_HW_ReadTimeAlarmFlag(g_rtcBasePointer[ins]);
}

/*!
 * @brief Read the next alarm time
 *
 * @param ins: The number of the RTC instance used
 * @param alarmTime: Pointer to the variable in which to store the data
 *
 * @retval STATUS_SUCCESS if the next alarm time is valid,
 *         STATUS_ERROR if there is no new alarm or alarm configuration specified.
 */
STATUS_T RTC_ReadNextAlarmTime(uint32_t ins, RTC_TIMEDATE_T *const alarmTime)
{
    ASSERT_INSTANCE(ins);

    STATUS_T status = STATUS_SUCCESS;
    uint32_t alarmInSec = 0;
    /* Check if is a new alarm and if true update alarm time date format from time seconds */
    if (G_RTCRUNTIMECONFIG[ins].isAlarmTimeNew == true)
    {
        alarmInSec = RTC_HW_ReadTimeAlarmRegister(g_rtcBasePointer[ins]);
        RTC_ConvertSecondsToTimeDate(&alarmInSec, alarmTime);
    }
    else
    {
        status = STATUS_ERROR;
    }
    /* Return the exit code */

    return status;
}

/*!
 * @brief This function configures the clock out pin source
 *
 * @param rtcBase: RTC base pointer
 * @param clkOutConfig: Source for the Clock Out pin
 *
 * @retval Returns the status of the operation,
 *         STATUS_SUCCESS if the configuration was successful,
 *         STATUS_ERROR if the ControlRegister is locked
 */
STATUS_T RTC_ConfigClockOut(RTC_T *const rtcBase, RTC_CLKOUT_CFG_T clkOutConfig)
{
    STATUS_T status = STATUS_SUCCESS;

    /*
     * Check if the Control Register is already locked,
     * if true, clock out configuration cannot be modified.
     */
    if (!RTC_HW_ReadCtrlRegLock(rtcBase))
    {
        switch (clkOutConfig)
        {
            case RTC_CLKOUT_DISABLED:
            {
                rtcBase->CTRL.reg &= ~0x1000000U;
            } break;
            case RTC_CLKOUT_SRC_TSIC:
            {
                rtcBase->CTRL.reg &= ~(0x1000000U | 0x20U);
                rtcBase->CTRL.reg |= ((((uint32_t)(((uint32_t)(1U)) << 24U)) & 0x1000000u) |
                            (((uint32_t)(((uint32_t)(0U)) << 5U)) & 0x20u));

            } break;
            case RTC_CLKOUT_SRC_32KHZ:
            {
                rtcBase->CTRL.reg &= ~(0x1000000U | 0x20U);
                rtcBase->CTRL.reg |= ((((uint32_t)(((uint32_t)(1U)) << 24U)) & 0x1000000u) |
                            (((uint32_t)(((uint32_t)(1U)) << 5U)) & 0x20u));
            } break;
            default:
            {
            } break;
        }
    }
    else
    {
        status = STATUS_ERROR;
    }
    /* Return the exit code */
    return status;
}

/*!
 * @brief This function set register lock status
 *
 * @param rtcBase: RTC base pointer
 * @param regLockSelect: Select register to lock
 *
 * @retval STATUS_SUCCESS if the lock was successful or if the register
 *         was already locked,
 *         STATUS_ERROR if the Lock Register is already locked or
 *         if the registerToConfig parameter is not a valid register.
 */
static STATUS_T RTC_SetupRegisterLock(RTC_T *const rtcBase, RTC_LOCK_REG_SEL_T regLockSelect)
{
    STATUS_T status = STATUS_SUCCESS;

    /* Check if the Lock Register is already locked,
     * if true, any other register lock status cannot
     * be modified.
     */
    if (!RTC_HW_ReadLockRegLock(rtcBase))
    {
        /* If the Lock Register is not locked we can
         * configure the register lock.
         */
        switch (regLockSelect)
        {
            case RTC_LOCK_REG_LOCK:
            {
                RTC_HW_LockRegLockIn(rtcBase);
            } break;
            case RTC_LOCK_REG_STATUS:
            {
                RTC_HW_StatusRegLockIn(rtcBase);
            } break;
            case RTC_LOCK_REG_CTRL:
            {
                RTC_HW_CtrlRegLockIn(rtcBase);
            } break;
            case RTC_LOCK_REG_TCL:
            {
                RTC_HW_TimeCompensationLockIn(rtcBase);
            } break;
            default:
            {
                status = STATUS_ERROR;
            } break;
        }
    }
    else
    {
        status = STATUS_ERROR;
    }
    /* Return the exit code */
    return status;
}

/*!
 * @brief This method configures register lock for the corresponding
 *        RTC instance.
 *
 * @param ins: The number of the RTC instance used
 * @param reglockConfig: Pointer to the lock configuration structure
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the Lock Register is locked.
 */
STATUS_T RTC_ConfigRegisterLock(uint32_t ins, const RTC_REGISTER_LOCK_CONFIG_T *const reglockConfig)
{
    ASSERT_INSTANCE(ins);

    /* Declare local variables */
    STATUS_T status = STATUS_SUCCESS;

    /* Lock the requested registers, but always the Lock register last,
     * otherwise other registers can not be locked.
     */

    /* Configure Control register lock */
    if (reglockConfig->ctrlRegLock)
    {
        status = RTC_SetupRegisterLock(g_rtcBasePointer[ins], RTC_LOCK_REG_CTRL);
    }
    /* Configure Time Compensation register lock */
    if (reglockConfig->timeCompensationRegisterLock)
    {
        status = RTC_SetupRegisterLock(g_rtcBasePointer[ins], RTC_LOCK_REG_TCL);
    }
    /* Configure Status register lock */
    if (reglockConfig->statusRegLock)
    {
        status = RTC_SetupRegisterLock(g_rtcBasePointer[ins], RTC_LOCK_REG_STATUS);
    }
    /* Configure Lock register lock */
    if (reglockConfig->lockRegLock)
    {
        status = RTC_SetupRegisterLock(g_rtcBasePointer[ins], RTC_LOCK_REG_LOCK);
    }

    /* Return the exit code */
    return status;
}

/*!
 * @brief Read which registers are locked for RTC instance
 *
 * @param ins: The number of the RTC instance used
 * @param reglockConfig: Pointer to the lock configuration structure in which to
 *                       save the data
 *
 * @retval None
 */
void RTC_ReadRegisterLock(uint32_t ins, RTC_REGISTER_LOCK_CONFIG_T *const reglockConfig)
{
    ASSERT_INSTANCE(ins);

    /* Get the configuration of the register lock */
    /* For the Lock Register */
    reglockConfig->lockRegLock = RTC_RegisterLockedVerify(g_rtcBasePointer[ins], RTC_LOCK_REG_LOCK);
    /* For the Control Register */
    reglockConfig->ctrlRegLock = RTC_RegisterLockedVerify(g_rtcBasePointer[ins], RTC_LOCK_REG_CTRL);
    /* For the Status Register */
    reglockConfig->statusRegLock = RTC_RegisterLockedVerify(g_rtcBasePointer[ins],
                                                            RTC_LOCK_REG_STATUS);
    /* For the Time Compensation Register */
    reglockConfig->timeCompensationRegisterLock = RTC_RegisterLockedVerify(g_rtcBasePointer[ins],
                                                                           RTC_LOCK_REG_TCL);
}

/*!
 * @brief This method configures the Time Seconds Interrupt with the
 *        configuration from the intConfig parameter.
 *
 * @param ins: The number of the RTC instance used
 * @param intConfig: Pointer to the structure which holds the configuration
 *
 * @retval None
 */
void RTC_SecondsIntConfig(uint32_t ins, RTC_SECONDS_INT_CONFIG_T *const intConfig)
{
    ASSERT_INSTANCE(ins);

    /* Disable the IRQ to avoid accidental interrupt requests */
    INT_SYS_DisableIRQ(g_rtcSecondsIrqNb[ins]);
    /* Disable the IRQ to avoid accidental interrupt requests */
    G_RTCRUNTIMECONFIG[ins].secondsIntConfig = intConfig;

    /* Configure the interrupt frequency */
    RTC_HW_ConfigTimeSecondsIntConf(g_rtcBasePointer[ins], intConfig->secondIntCfg);

    /* Enable or disable Time Seconds interrupt */
    RTC_HW_ConfigTimeSecondsIntEnable(g_rtcBasePointer[ins], intConfig->secondIntEnable);

    /* After the configuration is done, re-enable the interrupt in NVIC */
    INT_SYS_EnableIRQ(g_rtcSecondsIrqNb[ins]);
}

/*!
 * @brief This method configures fault interrupts such as:
 *        - Time Overflow Interrupt
 *        - Time Invalid Interrupt
 *        with the user provided configuration struct intConfig.
 *
 * @param ins: The number of the RTC instance used
 * @param intConfig: Pointer to the structure which holds the configuration
 *
 * @retval None
 */
void RTC_FaultIntConfig(uint32_t ins, RTC_INTERRUPT_CONFIG_T *const intConfig)
{
    ASSERT_INSTANCE(ins);

    /* Disable the IRQ to avoid accidental interrupt requests */
    INT_SYS_DisableIRQ(g_rtcIrqNumbers[ins]);
    /* Save the configuration into the ins's runtime structure */
    G_RTCRUNTIMECONFIG[ins].intConfig = intConfig;

    /* Enable or disable selected interrupts */
    RTC_HW_ConfigTimeOverflowIntEnable(g_rtcBasePointer[ins], intConfig->overflowIntEnable);

    RTC_HW_ConfigTimeInvalidIntEnable(g_rtcBasePointer[ins], intConfig->timeInvalidIntEnable);

    /* After the configuration is done, re-enable the interrupt in NVIC */
    INT_SYS_EnableIRQ(g_rtcIrqNumbers[ins]);
}

/*!
 * @brief This method is the API's Interrupt handler for generic and alarm IRQ.
 *
 * @details It will handle the alarm repetition and calls the user callbacks if they
 *          are not NULL.
 *
 * @param ins: RTC instance used
 *
 * @retval None
 */
void RTC_IRQHandler(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    uint32_t seconds_temp = 0;
    /* Get the alarm configuration */
    RTC_ALARM_CONFIG_T * alarmConfig = G_RTCRUNTIMECONFIG[ins].alarmConfig;
    /* Get the fault interrupt configuration */
    const RTC_INTERRUPT_CONFIG_T * const intConfig = G_RTCRUNTIMECONFIG[ins].intConfig;

    /* Check if an alarm has occurred */
    if (RTC_HW_ReadTimeAlarmFlag(g_rtcBasePointer[ins]) == true)
    {
        /* If the alarm interrupt configuration has been defined process the
         * alarm IRQ
         */
        if ((alarmConfig != NULL))
        {
            /* If recurrence is enabled modify the alarm register to the next
             * alarm.
             */
            if ((alarmConfig->numberOfRepeats <= 0U) && (alarmConfig->repeatForever == false))
            {
                /* If the alarm does not repeat,
                 * write 0 to TAR to clear the alarm flag.
                 */
                RTC_HW_AssignTimeAlarmRegister(g_rtcBasePointer[ins], 0UL);
                /* Set the internal variable which indicates that a new alarm is enabled to false */
                G_RTCRUNTIMECONFIG[ins].isAlarmTimeNew = false;
            }
            else
            {
                /* Get current time */
                seconds_temp = RTC_HW_ReadTimeSecondsRegister(g_rtcBasePointer[ins]);
                /* Current time is incremented with the repetition value */
                seconds_temp += alarmConfig->repetitionInterval - 1UL;
                /* Set new value to trigger the alarm */
                RTC_HW_AssignTimeAlarmRegister(g_rtcBasePointer[ins], seconds_temp);

                G_RTCRUNTIMECONFIG[ins].isAlarmTimeNew = true;
                /* If the alarm repeats forever, set number of repeats to 0
                 * to avoid an accidental trigger of the core overflow flag
                 */
                alarmConfig->numberOfRepeats = (alarmConfig->repeatForever == false) ?
                                                 (alarmConfig->numberOfRepeats - 1UL) : 0UL;
            }
            /* If the user has defined a callback, call it */
            if (alarmConfig->alarmCallback != NULL)
            {
                alarmConfig->alarmCallback(alarmConfig->callbackParams);
            }
        }
    }
    /* If the IRQ is not caused by the alarm then call the user callback if
     * defined.
     */
    else if ( intConfig != NULL )
    {
        if ( intConfig->rtcCallback != NULL )
       {
           /* Call the RTC interrupt callback function with callback parameter */
           intConfig->rtcCallback(intConfig->callbackParams);
       }
    }
    else
    {
      /* Do nothing */
    }
}

/*!
 * @brief This method is the API's Interrupt handler for RTC Second
 *        interrupt.
 *
 * @details This ISR will call the user callback if defined.
 *
 * @param ins: RTC instance used
 *
 * @retval None
 */
void RTC_SecondsIRQHandler(uint32_t ins)
{
    ASSERT_INSTANCE(ins);

    const RTC_SECONDS_INT_CONFIG_T *const secondIntCfg = G_RTCRUNTIMECONFIG[ins].secondsIntConfig;

    /* If the interrupt is configured by the driver API and the user callback
     * is not NULL, then call it.
     */
    if ((secondIntCfg != NULL) && (secondIntCfg->rtcSecondsCallback != NULL))
    {
        /* Call the RTC Seconds interrupt callback function with callback parameter */
        secondIntCfg->rtcSecondsCallback(secondIntCfg->secondsCallbackParams);
    }
}

/*!
 * @brief This method is the API's Interrupt handler for generic and alarm IRQ.
 *       It will handle the alarm repetition and calls the user callbacks if they
 *       are not NULL.
 *
 * @param ins: RTC instance used
 *
 * @retval None
 */
void RTC_IRQHandlerControl(void)
{
    RTC_IRQHandler(0U);
}

/*!
 * @brief This method is the API's Interrupt handler for RTC Second
 *        interrupt. This ISR will call the user callback if defined.
 *
 * @param ins: RTC instance used
 *
 * @retval None
 */
void RTC_Seconds_IRQHandlerControl(void)
{
    RTC_SecondsIRQHandler(0U);
}

/*******************************************************************************
 *                          PRIVATE FUNCTION
 *******************************************************************************/

/*!
 * @brief This function gets register lock status
 *
 * @param rtcBase: RTC base pointer
 * @param regLockConfig: The register for which to check lock status
 *
 * @retval True if the register is locked,
 *         false if it is not locked
 */
static bool RTC_RegisterLockedVerify(const RTC_T *const rtcBase, RTC_LOCK_REG_SEL_T regLockSelect)
{
    uint8_t state = false;
    switch (regLockSelect)
    {
        case RTC_LOCK_REG_LOCK:
        {
            state = RTC_HW_ReadLockRegLock(rtcBase);
        } break;
        case RTC_LOCK_REG_STATUS:
        {
            state = RTC_HW_ReadCtrlRegLock(rtcBase);
        } break;
        case RTC_LOCK_REG_CTRL:
        {
            state = RTC_HW_ReadStatusRegLock(rtcBase);
        } break;
        case RTC_LOCK_REG_TCL:
        {
            state = RTC_HW_ReadTimeCompensationLock(rtcBase);
        } break;
        default:
        {
        } break;
    }
    /* Return the exit code */
    return state;
}

/*******************************************************************************
 *                          HARDWARE ACCESS FUNCTIONS
 ******************************************************************************/

/*!
 * @brief Enable RTC instance counter
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the counter is enabled or if the time invalid flag is set.
 */
STATUS_T RTC_HW_Enable(RTC_T *const rtcBase)
{
    STATUS_T status = STATUS_SUCCESS;
    bool isCounterEnabled = false;

    /* Get the flags signaling if the counter is enabled */
    isCounterEnabled = RTC_HW_ReadTimeCounterState(rtcBase);

    /* Check if the RTC counter is enabled */
    if (!isCounterEnabled)
    {
        /* Enable oscillator and seconds counter */
        RTC_HW_EnableTimeCounter(rtcBase);
    }
    else
    {
        status = STATUS_ERROR;
    }
    /* Return the exit code */
    return status;
}

/*!
 * @brief Disable RTC instance counter
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval STATUS_SUCCESS if the operation was successful,
 *         STATUS_ERROR if the counter was not disabled.
 */
STATUS_T RTC_HW_Disable(RTC_T *const rtcBase)
{
    /* Check if counter is enabled and disable it */
    if (RTC_HW_ReadTimeCounterState(rtcBase) == true)
    {
        RTC_HW_DisableTimeCounter(rtcBase);
    }

    /* Read TCE bit to check if the counter is really disabled and return the
     * corresponding result.
     * - Error if the timer is still enabled (The register can be locked)
     * - Success if the timer is disabled
     */
    return (STATUS_T)(RTC_HW_ReadTimeCounterState(rtcBase) ? STATUS_ERROR : STATUS_SUCCESS);
}

/*!
 * @brief Assign time seconds register
 *
 * @param rtcBase: RTC base pointer
 * @param seconds: number of seconds passed
 *
 * @retval STATUS_SUCCESS if the write is succeeded,
 *         STATUS_ERROR if the counter is enabled.
 */
STATUS_T RTC_HW_AssignTimeSecondsRegister(RTC_T *const rtcBase, uint32_t seconds)
{
    STATUS_T status = STATUS_SUCCESS;

    if (RTC_HW_ReadTimeCounterState(rtcBase) == true)
    {
        status = STATUS_ERROR;
    }
    else
    {
        rtcBase->TIMSEC.reg  = seconds;
        status = STATUS_SUCCESS;
    }
    /* Return the exit code */
    return status;
}

/*!
 * @brief Read time seconds register value
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval Number of seconds passed
 */
uint32_t RTC_HW_ReadTimeSecondsRegister(const RTC_T *const rtcBase)
{
    return (uint32_t)((rtcBase->TIMSEC.reg & 0xFFFFFFFFU) >> 0U);
}

/*!
 * @brief Assign time alarm register
 *
 * @param rtcBase: RTC base pointer
 * @param seconds: Number of seconds at which the alarm is triggered. The TAR
 *                 value is correct only if the value is greater than current
 *                 time (Time seconds register)
 *
 * @retval None
 */
void RTC_HW_AssignTimeAlarmRegister(RTC_T *const rtcBase, uint32_t seconds)
{
    rtcBase->TIMALR.reg = seconds;
}

/*!
 * @brief Read time alarm register
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval Value in seconds of the Time Alarm Register
 */
uint32_t RTC_HW_ReadTimeAlarmRegister(const RTC_T *const rtcBase)
{
    return (uint32_t)((rtcBase->TIMALR.reg & 0xFFFFFFFFU) >> 0U);
}

/*!
 * @brief Assign time compensation
 *
 * @param rtcBase: RTC base pointer
 * @param compensationValue: the value which is subtracted from the counter
 *                           valid range -128, +127
 * @param compensationInterval: Compensation interval at which the compensation value
 *                              is added to the prescaler register
 *
 * @retval None
 */
void RTC_HW_AssignTimeCompensation(RTC_T *const rtcBase,
                                   int8_t compensationValue,
                                   uint8_t compensationInterval)
{
    uint32_t temp = rtcBase->TIMC.reg;
    temp &= ~(0xFFU | 0xFF00U);
    temp |= (uint32_t)(((uint32_t)compensationValue << 0U) & 0xFFU);
    temp |= (uint32_t)(((uint32_t)compensationInterval << 8U) & 0xFF00U);
    rtcBase->TIMC.reg = temp;
}

/*!
 * @brief Read the time compensation value and interval
 *
 * @param rtcBase: RTC base pointer
 * @param compensationValue: Current value which is subtracted from the counter
 *                           valid range -128, +127
 * @param compensationInterval: Current Compensation interval at which the compensation value
 *                              is added to the prescaler register
 *
 * @retval Current value used by the compensation logic for the present second interval
 */
void RTC_HW_ReadCurrentTimeCompensation(const RTC_T *const rtcBase,
                                        int8_t *compensationValue,
                                        uint8_t *compensationInterval)
{
    uint32_t temp = rtcBase->TIMC.reg;
    (*compensationValue) = (int8_t)((temp & 0xFF0000U) >> 16U);
    (*compensationInterval) = (uint8_t)((temp & 0xFF000000U) >> 24U);
}

/*!
 * @brief Pick clock source for RTC prescaler
 *
 * @param rtcBase: RTC base pointer
 * @param clkSelect: clock source
 *
 * @retval None
 */
void RTC_HW_PickLPOSelect(RTC_T *const rtcBase, RTC_CLK_SRC_SEL_T clkSelect)
{
    uint32_t temp = rtcBase->CTRL.reg;
    temp &= ~(0x80U);
    temp |= (uint32_t)(((uint32_t)clkSelect << 7U) & 0x80U);
    rtcBase->CTRL.reg = temp;
}

/*!
 * @brief Pick update mode of the registers when locked
 *
 * @param rtcBase: RTC base pointer
 * @param isUpdateEnable: value to be written in the register field:
 *        - true to enable writing of the registers when locked
 *        - false to disable writing of the registers when locked
 *
 * @retval None
 */
void RTC_HW_PickUpdateMode(RTC_T *const rtcBase, bool isUpdateEnable)
{
    uint32_t temp = rtcBase->CTRL.reg;
    temp &= ~(0x8U);
    temp |= (uint32_t)(((uint32_t)(isUpdateEnable ? 1UL : 0UL) << 3U) & 0x8U);
    rtcBase->CTRL.reg = temp;
}

/*!
 * @brief Reads the update mode of the registers when locked
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval Update mode value
 *         - true if writing of the registers when locked is enabled
 *         - false if writing of the registers when locked is disabled
 */
bool RTC_HW_ReadUpdateMode(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->CTRL.reg;
    temp = (temp & 0x8U) >> 3U;
    return ((temp == 1U) ? true : false);
}

/*!
 * @brief Pick Non-Supervisor access mode
 *
 * @param rtcBase: RTC base pointer
 * @param enable: supervisor access
 *        - if true Non-supervisor mode write accesses are supported.
 *        - if false Non-supervisor mode write accesses are not supported and
 *          generate a bus error.
 *
 * @retval None
 */
void RTC_HW_PickNonSupervisorAccess(RTC_T *const rtcBase, bool enable)
{
    uint32_t temp = rtcBase->CTRL.reg;
    temp &= ~(0x4U);
    temp |= (uint32_t)(((uint32_t)(enable ? 1UL : 0UL) << 2U) & 0x4U);
    rtcBase->CTRL.reg = temp;
}

/*!
 * @brief Active a software reset
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval None
 */
void RTC_HW_SoftwareReset(RTC_T *const rtcBase)
{
    rtcBase->CTRL.reg |= (uint32_t)(((uint32_t)1U << 0U) & 0x1U);
    rtcBase->CTRL.reg &= ~(uint32_t)(((uint32_t)1U << 0U) & 0x1U);
}

/*!
 * @brief Enable the time counter
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the counter
 *        - false to disable the counter
 *
 * @retval None
 */
void RTC_HW_EnableTimeCounter(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp &= ~(0x10U);
    temp |= (uint32_t)(((uint32_t)1U << 4U) & 0x10U);
    rtcBase->STS.reg = temp;
}

/*!
 * @brief Disable the time counter
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the counter
 *        - false to disable the counter
 *
 * @retval None
 */
void RTC_HW_DisableTimeCounter(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp &= ~(0x10U);
    rtcBase->STS.reg = temp;
}

/*!
 * @brief Read the time counter enable value.
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the counter enable bit
 *         - true if the counter is enabled
 *         - false if the counter is disabled
 */
bool RTC_HW_ReadTimeCounterState(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp = (temp & 0x10U) >> 4U;
    return ((temp == 1U) ? true : false);
}

/*!
 * @brief Get the time alarm flag
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the alarm flag
 *         - true if an alarm occurred
 *         - false if an alarm was not occurred
 */
bool RTC_HW_ReadTimeAlarmFlag(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp = (temp & 0x4U) >> 2U;
    return ((temp == 1U) ? true : false);
}

/*!
 * @brief Read time overflow flag
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the Time overflow flag
 *         - true if an overflow has occurred
 *         - false if an overflow has not occurred
 */
bool RTC_HW_ReadTimeOverflowFlag(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp = (temp & 0x2U) >> 1U;
    return ((temp == 1U) ? true : false);
}

/*!
 * @brief Read time invalid flag
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the time invalid flag
 *         - true if TIF is set
 *         - false if TIF is clear
 */
bool RTC_HW_ReadTimeInvalidFlag(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->STS.reg;
    temp = (temp & 0x1U) >> 0U;
    return ((temp == 1U) ? true : false);
}

/*!
 * @brief Lock in the lock register
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval None
 */
void RTC_HW_LockRegLockIn(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp &= ~(0x40U);
    rtcBase->LOCK.reg = temp;
}

/*!
 * @brief Read the lock register lock state
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the lock register lock
 *         - true if register is locked
 *         - false if the register is not locked
 */
bool RTC_HW_ReadLockRegLock(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp = (temp & 0x40U) >> 6U;
    return ((temp == 1U) ? false : true);
}

/*!
 * @brief Lock in the status register
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval None
 */
void RTC_HW_StatusRegLockIn(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp &= ~(0x20U);
    rtcBase->LOCK.reg = temp;
}

/*!
 * @brief Read the status register lock state
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the status register lock
 *         - true if register is locked
 *         - false if the register is not locked
 */
bool RTC_HW_ReadStatusRegLock(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp = (temp & 0x20U) >> 5U;
    return ((temp == 1U) ? false : true);
}

/*!
 * @brief Lock in the control register
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval None
 */
void RTC_HW_CtrlRegLockIn(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp &= ~(0x10U);
    rtcBase->LOCK.reg = temp;
}

/*!
 * @brief Read the control register lock state
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the Control register lock
 *         - true if register is locked
 *         - false if the register is not locked
 */
bool RTC_HW_ReadCtrlRegLock(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp = (temp & 0x10U) >> 4U;
    return ((temp == 1U) ? false : true);
}

/*!
 * @brief Lock in the time compensation register
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval None
 */
void RTC_HW_TimeCompensationLockIn(RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp &= ~(0x8U);
    rtcBase->LOCK.reg = temp;
}

/*!
 * @brief Read the time compensation register lock state
 *
 * @param rtcBase: RTC base pointer
 *
 * @retval State of the Time Compensation register lock
 *         - true if register is locked
 *         - false if the register is not locked
 */
bool RTC_HW_ReadTimeCompensationLock(const RTC_T *const rtcBase)
{
    uint32_t temp = rtcBase->LOCK.reg;
    temp = (temp & 0x8U) >> 3U;
    return ((temp == 1U) ? false : true);
}

/*!
 * @brief Configure time seconds interrupt
 *
 * @param rtcBase: RTC base pointer
 * @param intConfig: Select at which frequency the interrupt will occur
 *
 * @retval None
 */
void RTC_HW_ConfigTimeSecondsIntConf(RTC_T *const rtcBase, RTC_SECOND_INT_CFG_T intConfig)
{
    uint32_t temp = rtcBase->IEN.reg;
    temp &= ~(0x70000U);
    temp |= (uint32_t)(((uint32_t)intConfig << 16U) & 0x70000U);
    rtcBase->IEN.reg = temp;
}

/*!
 * @brief Enable time seconds interrupt
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the interrupt
 *        - false to disable the interrupt
 * @details None
 */
void RTC_HW_ConfigTimeSecondsIntEnable(RTC_T *const rtcBase, bool enable)
{
    uint32_t temp = rtcBase->IEN.reg;
    temp &= ~(0x10U);
    temp |= (uint32_t)(((uint32_t)(enable ? 1UL : 0UL) << 4U) & 0x10U);
    rtcBase->IEN.reg = temp;
}

/*!
 * @brief Enable time alarm interrupt
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the interrupt
 *        - false to disable the interrupt
 *
 * @retval None
 */
void RTC_HW_ConfigTimeAlarmIntEnable(RTC_T *const rtcBase, bool enable)
{
    uint32_t temp = rtcBase->IEN.reg;
    temp &= ~(0x4U);
    temp |= (uint32_t)(((uint32_t)(enable ? 1UL : 0UL) << 2U) & 0x4U);
    rtcBase->IEN.reg = temp;
}

/*!
 * @brief Enable time overflow interrupt
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the interrupt
 *        - false to disable the interrupt
 *
 * @retval None
 */
void RTC_HW_ConfigTimeOverflowIntEnable(RTC_T *const rtcBase, bool enable)
{
    uint32_t temp = rtcBase->IEN.reg;
    temp &= ~(0x2U);
    temp |= (uint32_t)(((uint32_t)(enable ? 1UL : 0UL) << 1U) & 0x2U);
    rtcBase->IEN.reg = temp;
}

/*!
 * @brief Enable time invalid interrupt
 *
 * @param rtcBase: RTC base pointer
 * @param enable:
 *        - true to enable the interrupt
 *        - false to disable it
 *
 * @retval None
 */
void RTC_HW_ConfigTimeInvalidIntEnable(RTC_T *const rtcBase, bool enable)
{
    uint32_t temp = rtcBase->IEN.reg;
    temp &= ~(0x1U);
    temp |= (uint32_t)(((uint32_t)(enable ? 1UL : 0UL) << 0U) & 0x1U);
    rtcBase->IEN.reg = temp;
}

/**@} end of group RTC_Functions*/
/**@} end of group RTC_Driver*/
/**@} end of group APM32F445_446_StdPeriphDriver*/
