/**
  **********************************************************************************************************************
  * @file    stm32c5xx_hal_crs.c
  * @brief   CRS HAL module driver.
  **********************************************************************************************************************
  * @attention
  *
  * Copyright (c) 2026 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  **********************************************************************************************************************
  */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "stm32_hal.h"

/** @addtogroup STM32C5xx_HAL_Driver
  * @{
  */
#if defined (CRS)
#if defined(USE_HAL_CRS_MODULE) && (USE_HAL_CRS_MODULE == 1U)

/** @addtogroup CRS
  * @{
  */
/** @defgroup CRS_Introduction CRS Introduction
  * @{

The clock recovery system (CRS) is an advanced digital controller acting on the internal fine-grained trimmable
RC oscillator HSI144.
The CRS provides a means to evaluate the oscillator output frequency based on comparison with a selectable
synchronization signal.
The oscillator trimming can be automatically adjusted based on the measured frequency error value, while still allowing
manual trimming when required.
The CRS is ideally suited to provide a precise clock to the USB peripheral. In such a case, the synchronization signal
can be derived from the start-of-frame (SOF) packet signaling on the USB bus,
which is sent by a USB host at 1 ms intervals.
The synchronization signal can also be derived from the LSE oscillator output, or it can be generated by user software.

# Main features
The main features of CRS are described below:
- Selectable synchronization source with programmable prescaler and polarity:
  - LSE oscillator output
  - USB SOF packet reception
- Possibility to generate synchronization pulses by software
- Automatic oscillator trimming capability with no need for CPU action
- Manual control option for faster start-up convergence
- 16-bit frequency error counter with automatic error value capture and reload
- Programmable limit for automatic frequency error value evaluation and status reporting
- Maskable interrupts/events:
 - Expected synchronization (ESYNC)
 - Synchronization OK (SYNCOK)
 - Synchronization warning (SYNCWARN)
 - Synchronization or trimming error (ERR)

  */

/**
  * @}
  */

/** @defgroup CRS_How_To_Use CRS How To Use
  * @{

# How to use the HAL CRS driver

## The HAL CRS driver can be used as follows:
- Enable HSI144 in the system clock configuration.
- Initialize the CRS handle with HAL_CRS_Init().
  Enable the CRS clock by setting USE_HAL_CRS_CLK_ENABLE_MODEL to HAL_CLK_ENABLE_PERIPH_ONLY.
- Set the configuration of the CRS to choose the source, the input polarity, the divider of the selected source,
  the reload value, the frequency error limit value, and whether to use automatic trimming with HAL_CRS_SetConfig().
  This operation is optional. Keep the default configuration if it is suitable.
  Retrieve the default configuration by calling HAL_CRS_ResetConfig().
  You can also use the @ref HAL_CRS_CALCULATE_RELOAD macro to calculate the reload value directly from the target
  and synchronization frequencies.
  Note: When using USB LPM (Link Power Management) and the device is in Sleep mode, the periodic USB SOF is not
  generated by the host.
  Therefore, no synchronization signal is provided to the CRS to calibrate the HSI144 while running.
  To guarantee the required clock precision after waking up from Sleep mode, use the LSE or reference clock on the GPIOs
  as the synchronization signal.

### Polling mode operation:
- Start the CRS driver with HAL_CRS_StartSync() to enable the frequency error counter.
- Use HAL_CRS_PollForSync() to wait for complete synchronization.
  Based on the status, adjust the trimming or the synchronization source, or continue the application if synchronization
  is OK.
  Retrieve error codes with HAL_CRS_GetLastErrorCodes() and information related to synchronization with
  HAL_CRS_GetFrequencyErrorInfo().
- To update error codes and synchronization information, call HAL_CRS_StopSync() before changing the synchronization
  configuration with HAL_CRS_SetConfig(), then call HAL_CRS_StartSync() again.
  Note: When the synchronization event is detected during the downcounting phase (before reaching the zero value),
  this means that the actual frequency is lower than the target, so the trimming value must be incremented.
  When it is detected during the upcounting phase, this means that the actual frequency is higher, so the trimming value
  must be decremented.

### Interrupt mode operation:
 - Override the weak definitions for the following callbacks:
   - HAL_CRS_SyncOkCallback()
   - HAL_CRS_SyncWarnCallback()
   - HAL_CRS_ExpectedSyncCallback()
   - HAL_CRS_ErrorCallback()
 - Or register callbacks:
   - HAL_CRS_RegisterSyncOkCallback()
   - HAL_CRS_RegisterSyncWarnCallback()
   - HAL_CRS_RegisterExpectedSyncCallback()
   - HAL_CRS_RegisterErrorCallback()
 - Start the CRS driver with HAL_CRS_StartSync_IT() to enable the interrupt sources and receive callbacks.
 - This triggers the overridden weak callbacks or the registered callbacks from HAL_CRS_IRQHandler().

### Generate a software synchronization:
To force a synchronization event, call HAL_CRS_GenerateSoftwareSync().
You can call this function before HAL_CRS_SetConfig() (for example, in the SysTick handler).

### HAL CRS Driver State:

- Use HAL_CRS_GetState() to return the HAL CRS state.
  */
/**
  * @}
  */

/** @defgroup CRS_Configuration_Table CRS Configuration Table
  * @{

# Configuration inside the CRS driver
Configuration defines        | Description           | Default value     | Note
------------------------------| --------------------- | ------------------| -------------------------------------------
USE_ASSERT_DBG_PARAM          | from Preprocessor env | NONE              | Enable parameter checks for HAL
USE_ASSERT_DBG_STATE          | from Preprocessor env | NONE              | Enable state checks for HAL
USE_HAL_CHECK_PARAM           | from hal_conf.h       | 0U                | When set, parameters are checked at runtime
USE_HAL_CRS_MODULE            | from hal_conf.h       | 1U                | Enable the HAL CRS module
USE_HAL_CRS_CLK_ENABLE_MODEL  | from hal_conf.h       | HAL_CLK_ENABLE_NO | Enable peripheral clock gating
USE_HAL_CRS_GET_LAST_ERRORS   | from hal_conf.h       | 0U                | Enable retrieval of the last process error
USE_HAL_CRS_REGISTER_CALLBACKS| from hal_conf.h       | 0U                | Allow the user to define custom callbacks
USE_HAL_CRS_USER_DATA         | from hal_conf.h       | 0U                | When set, user data is defined in the handle
  */
/**
  * @}
  */

/* Private types -----------------------------------------------------------------------------------------------------*/
/* Private constants -------------------------------------------------------------------------------------------------*/
/** @defgroup CRS_Private_Constants CRS Private Constants
  * @{
  */
#define CRS_SYNC_SOURCE_DEFAULT LL_CRS_SYNC_SOURCE_USB      /*!< Default synchronization source */
/**
  * @}
  */
/* Private macros ----------------------------------------------------------------------------------------------------*/
/** @defgroup CRS_Private_Macros CRS Private Macros
  * @{
  */
/**
  * @brief Synchronization source
  */
#define IS_CRS_SYNC_SOURCE(source) (((source) == HAL_CRS_SYNC_SOURCE_GPIO) \
                                    || ((source) == HAL_CRS_SYNC_SOURCE_LSE) \
                                    || ((source) == HAL_CRS_SYNC_SOURCE_USB) \
                                    || ((source) == HAL_CRS_SYNC_SOURCE_HSE_1MHZ))

/**
  * @brief Synchronization divider
  */
#define IS_CRS_SYNC_DIVIDER(div)       (((div) == HAL_CRS_SYNC_DIV1) || ((div) == HAL_CRS_SYNC_DIV2) \
                                        || ((div) == HAL_CRS_SYNC_DIV4) || ((div) == HAL_CRS_SYNC_DIV8) \
                                        || ((div) == HAL_CRS_SYNC_DIV16) || ((div) == HAL_CRS_SYNC_DIV32) \
                                        || ((div) == HAL_CRS_SYNC_DIV64) || ((div) == HAL_CRS_SYNC_DIV128))

/**
  * @brief Synchronization polarity
  */
#define IS_CRS_SYNC_POLARITY(polarity)     (((polarity) == HAL_CRS_SYNC_POLARITY_RISING) \
                                            || ((polarity) == HAL_CRS_SYNC_POLARITY_FALLING))

/**
  * @brief Reload
  */
#define IS_CRS_RELOAD(value)  (((value) <= 0xFFFFU))

/**
  * @brief Frequency error limit
  */
#define IS_CRS_FREQUENCY_ERROR_LIMIT(value)   (((value) <= 0xFFU))

/**
  * @brief Trimming
  */
#define IS_CRS_TRIMMING(value) (((value) <= 0x5FU))

/**
  * @brief Auto trimming
  */
#define IS_CRS_AUTO_TRIMMING(state)            (((state) == HAL_CRS_AUTO_TRIMMING_DISABLE) \
                                                || ((state) == HAL_CRS_AUTO_TRIMMING_ENABLE))

/**
  * @brief Instance
  */
#define CRS_INSTANCE(hcrs)            ((CRS_TypeDef *)((uint32_t)(hcrs)->instance))

/**
  * @}
  */

/* Private functions -------------------------------------------------------------------------------------------------*/
/* Private variables -------------------------------------------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------------------------------------------------*/
/** @addtogroup CRS_Exported_Functions
  * @{
  */

/** @addtogroup CRS_Exported_Functions_Group1
  * @{

This section provides a set of functions allowing to initialize and deinitialize the CRS peripheral:

- Call the function HAL_CRS_Init() to initialize the selected CRS handle and associate an instance.
- Call the function HAL_CRS_DeInit() to deinitialize the CRS.
  */

/**
  * @brief  Initialize the CRS according to the associated handle.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS.
  * @param  instance CRS instance.
  * @retval HAL_INVALID_PARAM When the handle is NULL.
  * @retval HAL_OK            HAL CRS driver correctly initialized for the given CRS instance.
  */
hal_status_t HAL_CRS_Init(hal_crs_handle_t *hcrs, hal_crs_t instance)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(IS_CRS_ALL_INSTANCE((CRS_TypeDef *)(uint32_t)instance));

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the handle struct pointer */
  if (hcrs == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  hcrs->instance = instance;

#if defined(USE_HAL_CRS_CLK_ENABLE_MODEL) && (USE_HAL_CRS_CLK_ENABLE_MODEL > HAL_CLK_ENABLE_NO)
  HAL_RCC_CRS_EnableClock();
#endif /* USE_HAL_CRS_CLK_ENABLE_MODEL */

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
  /* Initialize the CRS callback settings */
  hcrs->p_error_cb         = HAL_CRS_ErrorCallback;        /* Error callback */
  hcrs->p_sync_ok_cb       = HAL_CRS_SyncOkCallback;       /* Synchronization ok callback */
  hcrs->p_sync_warn_cb     = HAL_CRS_SyncWarnCallback;     /* Synchronization warning callback */
  hcrs->p_expected_sync_cb = HAL_CRS_ExpectedSyncCallback; /* Expected synchronization callback */
#endif  /* USE_HAL_CRS_REGISTER_CALLBACKS */

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
  hcrs->last_error_codes = HAL_CRS_ERROR_NONE;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

  hcrs->global_state = HAL_CRS_STATE_IDLE;

  return HAL_OK;
}

/**
  * @brief  DeInitialize the CRS.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  */
void HAL_CRS_DeInit(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(IS_CRS_ALL_INSTANCE((CRS_TypeDef *)(uint32_t)hcrs->instance));

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  /* Stop the CRS */
  LL_CRS_DisableFreqErrorCounter(CRS_INSTANCE(hcrs));

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
  hcrs->last_error_codes = HAL_CRS_ERROR_NONE;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

  hcrs->global_state = HAL_CRS_STATE_RESET;
}

/**
  * @}
  */

/** @addtogroup CRS_Exported_Functions_Group2
  * @{

This section provides a set of functions allowing you to configure the CRS driver:

- Call the function HAL_CRS_SetConfig() to set the different fields needed before starting the CRS driver.
- Call the function HAL_CRS_GetConfig() to retrieve the configuration.
- Call the function HAL_CRS_ResetConfig() to reset the configuration to its default values.
- Call the function HAL_CRS_SetTrimming() to set the trimming value.
- Call the function HAL_CRS_GetTrimming() to retrieve the trimming value.
- Call the function HAL_CRS_GetFrequencyErrorInfo() to retrieve frequency error information.
  */

/**
  * @brief  Configure the CRS driver.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @param  p_config Pointer on @ref hal_crs_config_t structure.
  * @note   This function is optional, the user can start the driver with the default configuration.
  * @retval HAL_OK CRS instance has been correctly configured.
  * @retval HAL_INVALID_PARAM When the p_config pointer is NULL.
  */
hal_status_t HAL_CRS_SetConfig(const hal_crs_handle_t *hcrs, const hal_crs_config_t *p_config)
{
  CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_config != NULL);

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the config struct pointer */
  if (p_config == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  ASSERT_DBG_PARAM(IS_CRS_SYNC_DIVIDER(p_config->divider));
  ASSERT_DBG_PARAM(IS_CRS_SYNC_SOURCE(p_config->source));
  ASSERT_DBG_PARAM(IS_CRS_SYNC_POLARITY(p_config->polarity));
  ASSERT_DBG_PARAM(IS_CRS_RELOAD(p_config->reload));
  ASSERT_DBG_PARAM(IS_CRS_FREQUENCY_ERROR_LIMIT(p_config->frequency_error_limit));
  ASSERT_DBG_PARAM(IS_CRS_TRIMMING(p_config->trimming));
  ASSERT_DBG_PARAM(IS_CRS_AUTO_TRIMMING(p_config->auto_trimming));

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

  p_crsx = CRS_INSTANCE(hcrs);

  LL_CRS_ConfigTrimming(p_crsx, p_config->trimming, (uint32_t)p_config->auto_trimming);

  LL_CRS_ConfigSynchronization(p_crsx, (uint32_t)p_config->divider | (uint32_t)p_config->source |
                               (uint32_t)p_config->polarity, p_config->reload, p_config->frequency_error_limit);
  return HAL_OK;
}

/**
  * @brief  Get the configuration.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @param  p_config Pointer on @ref hal_crs_config_t structure.
  */
void HAL_CRS_GetConfig(const hal_crs_handle_t *hcrs, hal_crs_config_t *p_config)
{
  const CRS_TypeDef *p_crsx;
  uint32_t config;
  uint32_t trimming_config;

  ASSERT_DBG_PARAM(hcrs != NULL);
  /* Check config allocation */
  ASSERT_DBG_PARAM(p_config != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  p_crsx = (const CRS_TypeDef *)((uint32_t)hcrs->instance);

  config = LL_CRS_READ_REG(p_crsx, CFGR);
  trimming_config = LL_CRS_READ_REG(p_crsx, CR);

  p_config->divider = (hal_crs_sync_div_t)(uint32_t)(config & CRS_CFGR_SYNCDIV);
  p_config->source = (hal_crs_sync_source_t)(uint32_t)(config & CRS_CFGR_SYNCSRC);
  p_config->polarity = (hal_crs_sync_polarity_t)(uint32_t)(config & CRS_CFGR_SYNCPOL);
  p_config->reload = (config & CRS_CFGR_RELOAD);
  p_config->frequency_error_limit = ((config & CRS_CFGR_FELIM) >> CRS_CFGR_FELIM_Pos);
  p_config->trimming = ((trimming_config & CRS_CR_TRIM) >> CRS_CR_TRIM_Pos);
  p_config->auto_trimming = (hal_crs_auto_trimming_state_t)(uint32_t)(trimming_config & CRS_CR_AUTOTRIMEN);
}

/**
  * @brief  Reset the following fields to their default values:
  *         - The divider is set to not divided.
  *         - The source is set to signal source 3.
  *         - The polarity is set to rising edge.
  *         - The reload is set to 0xBB7FU.
  *         - The felim is set to 0x22U.
  *         - The trimming is set to 0x30U.
  *         - The auto trimming is disabled.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  */
void HAL_CRS_ResetConfig(const hal_crs_handle_t *hcrs)
{
  CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

  p_crsx = CRS_INSTANCE(hcrs);

  LL_CRS_DisableAutoTrimming(p_crsx);


  /* Reset the Control Register: trimming set to 0x30U and auto trimming disabled */
  LL_CRS_ConfigTrimming(p_crsx, LL_CRS_HSI144CALIBRATION_DEFAULT, LL_CRS_AUTO_TRIMMING_DISABLE);
  /**
    * Reset the Configuration Register: divider set to not divided, source set to signal source 3,
    * polarity set to rising edge, felim set to 0x22U and reload set to 0xBB7FU
    */
  LL_CRS_ConfigSynchronization(p_crsx, LL_CRS_SYNC_DIV_1 | CRS_SYNC_SOURCE_DEFAULT | LL_CRS_SYNC_POLARITY_RISING,
                               LL_CRS_RELOADVALUE_DEFAULT, LL_CRS_ERRORLIMIT_DEFAULT);

  /* Reset the Interrupt Flag Clear Register: clear ESYNC, ERR, SYNCWARN and SYNCOK flags */
  LL_CRS_ClearFlag(p_crsx, (LL_CRS_ICR_SYNCOKC | LL_CRS_ICR_SYNCWARNC | LL_CRS_ICR_ERRC | LL_CRS_ICR_ESYNCC));
}

/**
  * @brief  Set the trimming value.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @param  trimming Trimming value.
  * @retval HAL_OK CRS instance has been correctly configured.
  * @retval HAL_ERROR Auto trimming enabled, configuration not possible.
  */
hal_status_t HAL_CRS_SetTrimming(const hal_crs_handle_t *hcrs, uint32_t trimming)
{
  CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(IS_CRS_TRIMMING(trimming));

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

  p_crsx = CRS_INSTANCE(hcrs);

  /* Check if the auto trimming is disabled */
  if (LL_CRS_IsEnabledAutoTrimming(p_crsx) != 0U)
  {
    return HAL_ERROR;
  }
  LL_CRS_SetHSI144SmoothTrimming(p_crsx, trimming);
  return HAL_OK;
}

/**
  * @brief  Get the trimming value.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @retval uint32_t Trimming value.
  */
uint32_t HAL_CRS_GetTrimming(const hal_crs_handle_t *hcrs)
{
  const CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  p_crsx = (const CRS_TypeDef *)((uint32_t)hcrs->instance);
  return (LL_CRS_GetHSI144SmoothTrimming(p_crsx));
}

/**
  * @brief  Get frequency error information (frequency error capture and direction).
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @param  p_frequency_error_info Pointer on @ref hal_crs_frequency_error_info_t structure.
  */
void HAL_CRS_GetFrequencyErrorInfo(const hal_crs_handle_t *hcrs,
                                   hal_crs_frequency_error_info_t *p_frequency_error_info)
{
  const CRS_TypeDef *p_crsx;
  uint32_t info;

  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_frequency_error_info != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  p_crsx = (const CRS_TypeDef *)((uint32_t)hcrs->instance);

  info = LL_CRS_GetFreqErrorInfo(p_crsx);

  /* Get Frequency error capture */
  p_frequency_error_info->frequency_error_capture = LL_CRS_READ_FREQ_ERROR_CAPTURE(info);

  /* Get Frequency error direction */
  p_frequency_error_info->frequency_error_dir = (hal_crs_frequency_error_dir_t)(uint32_t)
                                                LL_CRS_READ_FREQ_ERROR_DIRECTION(info);
}

/**
  * @}
  */

/** @addtogroup CRS_Exported_Functions_Group3
  * @{

This section provides a set of functions allowing you to start and stop the CRS driver and control auto trimming:

- Call the functions HAL_CRS_EnableAutoTrimming(), HAL_CRS_DisableAutoTrimming(), and HAL_CRS_IsEnabledAutoTrimming()
  to enable or disable auto trimming and to check whether it is enabled.
- Call the function HAL_CRS_StartSync() to enable the frequency error counter.
- Call the function HAL_CRS_StopSync() to disable the frequency error counter.
- Call the function HAL_CRS_StartSync_IT() to enable the frequency error counter with interrupt sources.
- Call the function HAL_CRS_StopSync_IT() to disable the frequency error counter with interrupt sources.
  */

/**
  * @brief  Enable the auto trimming.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @retval HAL_OK CRS auto trimming has been correctly activated.
  */
hal_status_t HAL_CRS_EnableAutoTrimming(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  LL_CRS_EnableAutoTrimming(CRS_INSTANCE(hcrs));

  return HAL_OK;
}

/**
  * @brief  Disable the auto trimming.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @retval HAL_OK CRS auto trimming has been correctly de-activated.
  */
hal_status_t HAL_CRS_DisableAutoTrimming(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  LL_CRS_DisableAutoTrimming(CRS_INSTANCE(hcrs));

  return HAL_OK;
}

/**
  * @brief  Get the auto trimming status.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @retval HAL_CRS_AUTO_TRIMMING_DISABLED
  * @retval HAL_CRS_AUTO_TRIMMING_ENABLED
  */
hal_crs_auto_trimming_status_t HAL_CRS_IsEnabledAutoTrimming(const hal_crs_handle_t *hcrs)
{
  const CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  p_crsx = (const CRS_TypeDef *)((uint32_t)hcrs->instance);

  return (hal_crs_auto_trimming_status_t)LL_CRS_IsEnabledAutoTrimming(p_crsx);
}

/**
  * @brief  Start the CRS in Polling mode.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function enables the frequency error counter.
  * @retval HAL_OK Operation completed successfully.
  */
hal_status_t HAL_CRS_StartSync(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
  hcrs->last_error_codes = HAL_CRS_ERROR_NONE;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

  LL_CRS_EnableFreqErrorCounter(CRS_INSTANCE(hcrs));

  hcrs->global_state = HAL_CRS_STATE_ACTIVE;

  return HAL_OK;
}

/**
  * @brief  Stop the CRS in Polling mode.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function disables the frequency error counter.
  * @retval HAL_OK Operation completed successfully.
  */
hal_status_t HAL_CRS_StopSync(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_ACTIVE);

  LL_CRS_DisableFreqErrorCounter(CRS_INSTANCE(hcrs));

  hcrs->global_state = HAL_CRS_STATE_IDLE;

  return HAL_OK;
}

/**
  * @brief  Start the CRS in Interrupt mode.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function enables the interrupt sources and the frequency error counter.
  * @retval HAL_OK Operation completed successfully.
  */
hal_status_t HAL_CRS_StartSync_IT(hal_crs_handle_t *hcrs)
{
  CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

  p_crsx = CRS_INSTANCE(hcrs);

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
  hcrs->last_error_codes = HAL_CRS_ERROR_NONE;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

  LL_CRS_EnableIT(p_crsx, (LL_CRS_CR_SYNCOKIE | LL_CRS_CR_SYNCWARNIE | LL_CRS_CR_ERRIE | LL_CRS_CR_ESYNCIE));

  LL_CRS_EnableFreqErrorCounter(p_crsx);

  hcrs->global_state = HAL_CRS_STATE_ACTIVE;

  return HAL_OK;
}

/**
  * @brief  Stop the CRS in Interrupt mode.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function disables the interrupt sources and the frequency error counter.
  * @retval HAL_OK Operation completed successfully.
  */
hal_status_t HAL_CRS_StopSync_IT(hal_crs_handle_t *hcrs)
{
  CRS_TypeDef *p_crsx;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_ACTIVE);

  p_crsx = CRS_INSTANCE(hcrs);

  LL_CRS_DisableFreqErrorCounter(p_crsx);

  LL_CRS_DisableIT(p_crsx, (LL_CRS_CR_SYNCOKIE | LL_CRS_CR_SYNCWARNIE | LL_CRS_CR_ERRIE | LL_CRS_CR_ESYNCIE));

  LL_CRS_ClearFlag(p_crsx, (LL_CRS_ICR_SYNCOKC | LL_CRS_ICR_SYNCWARNC | LL_CRS_ICR_ERRC | LL_CRS_ICR_ESYNCC));

  hcrs->global_state = HAL_CRS_STATE_IDLE;

  return HAL_OK;
}

/**
  * @}
  */

/** @addtogroup CRS_Exported_Functions_Group4
  * @{

This section provides a set of process functions:

- Call the function HAL_CRS_GenerateSoftwareSync() to generate a software synchronization event.
- Call the function HAL_CRS_PollForSync() to retrieve the status of the synchronization event.
  */

/**
  * @brief  Generate the software synchronization event.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @retval HAL_OK Operation completed successfully.
  */
hal_status_t HAL_CRS_GenerateSoftwareSync(hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_IDLE);

  LL_CRS_GenerateEvent_SWSYNC(CRS_INSTANCE(hcrs));

  return HAL_OK;
}

/**
  * @brief  Retrieve the status of synchronization.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @param timeout_ms  Duration of the timeout in milliseconds.
  * @note  timeout_ms is based on the maximum time to receive a SYNC event based on synchronization
  *        frequency.
  * @warning  If timeout_ms is set to HAL_MAX_DELAY, HAL_TIMEOUT is never returned.
  * @retval HAL_OK Synchronization event OK (SYNCOK).
  * @retval HAL_ERROR Synchronization error or warning (SYNCERR, TRIMOVF, SYNCMISS or SYNCWARN).
  * @retval HAL_TIMEOUT Timeout elapsed.
  */
hal_status_t HAL_CRS_PollForSync(hal_crs_handle_t *hcrs, uint32_t timeout_ms)
{
  CRS_TypeDef *p_crsx;
  uint32_t tickstart;
  uint32_t flags;

  ASSERT_DBG_PARAM(hcrs != NULL);

  ASSERT_DBG_STATE(hcrs->global_state, HAL_CRS_STATE_ACTIVE);

  p_crsx = CRS_INSTANCE(hcrs);

  /* Get timeout */
  tickstart = HAL_GetTick();

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
  hcrs->last_error_codes = HAL_CRS_ERROR_NONE;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

  do
  {
    flags = LL_CRS_READ_REG(p_crsx, ISR);

    /* Check CRS Expected SYNC flag */
    if ((flags & LL_CRS_ISR_ESYNCF) != 0U)
    {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
      hcrs->last_error_codes |= HAL_CRS_ERROR_EXPECTED_SYNC;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

      LL_CRS_ClearFlag_ESYNC(p_crsx);
    }

    /* Check CRS SYNCOK flag */
    if ((flags & LL_CRS_ISR_SYNCOKF) != 0U)
    {
      LL_CRS_ClearFlag_SYNCOK(p_crsx);

      return HAL_OK;
    }

    /* Check CRS ERR and SYNCWARN flags */
    if (((flags & LL_CRS_ISR_ERRF) == 0U) && ((flags & LL_CRS_ISR_SYNCWARNF) == 0U))
    {
      flags = 0U;
    }
    else /* Error flag or SYNC warning flag set */
    {
      if ((flags & LL_CRS_ISR_TRIMOVF) != 0U)
      {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
        hcrs->last_error_codes |= HAL_CRS_ERROR_TRIMMING;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
      }

      if ((flags & LL_CRS_ISR_SYNCERR) != 0U)
      {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
        hcrs->last_error_codes |= HAL_CRS_ERROR_SYNC_ERROR;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
      }

      if ((flags & LL_CRS_ISR_SYNCMISS) != 0U)
      {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
        hcrs->last_error_codes |= HAL_CRS_ERROR_SYNC_MISSED;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
      }

      if ((flags & LL_CRS_ISR_SYNCWARNF) != 0U)
      {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
        hcrs->last_error_codes |= HAL_CRS_ERROR_SYNC_WARN;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
      }

      LL_CRS_ClearFlag(p_crsx, LL_CRS_ICR_ERRC | LL_CRS_ICR_SYNCWARNC);
    }

    if (timeout_ms != HAL_MAX_DELAY)
    {
      if (((HAL_GetTick() - tickstart) > timeout_ms) || (timeout_ms == 0U))
      {
        return HAL_TIMEOUT;
      }
    }
  } while (flags == 0U);

  return HAL_ERROR;
}

/**
  * @}
  */

/** @addtogroup CRS_Exported_Functions_Group5
  * @{

This section provides functions allowing you to:
 - Handle the CRS interrupt request with HAL_CRS_IRQHandler().
There are two ways to use callbacks: override weak callback functions or register user callback functions.
They indicate:
 - When the CRS driver encounters an error (HAL_CRS_ErrorCallback() or callback function registered with
   HAL_CRS_RegisterErrorCallback()). The errors can be synchronization missed, synchronization error or
   trimming overflow or underflow.
 - When a synchronization event OK is triggered (HAL_CRS_SyncOkCallback()
   or callback function registered with HAL_CRS_RegisterSyncOkCallback()).
 - When a synchronization warning is triggered (HAL_CRS_SyncWarnCallback()
   or callback function registered with HAL_CRS_RegisterSyncWarnCallback()).
 - When an expected synchronization is triggered (HAL_CRS_ExpectedSyncCallback()
   or callback function registered with HAL_CRS_RegisterExpectedSyncCallback()).
  */

/**
  * @brief  Handle the Clock Recovery System interrupt request.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note  This function must be called from CRS_IRQHandler().
  */
void HAL_CRS_IRQHandler(hal_crs_handle_t *hcrs)
{
  CRS_TypeDef *p_crsx;
  uint32_t it_flags_sources;

  ASSERT_DBG_PARAM(hcrs != NULL);

  p_crsx = CRS_INSTANCE(hcrs);

  /* Get current IT flags and IT sources values */
  it_flags_sources = LL_CRS_READ_REG(p_crsx, ISR);
  it_flags_sources &= LL_CRS_READ_REG(p_crsx, CR);

  /* Check CRS SYNCOK flag  */
  if ((it_flags_sources & LL_CRS_ISR_SYNCOKF) != 0U)
  {
    LL_CRS_ClearFlag_SYNCOK(p_crsx);

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
    hcrs->p_sync_ok_cb(hcrs);
#else
    HAL_CRS_SyncOkCallback(hcrs);
#endif /* USE_HAL_CRS_REGISTER_CALLBACKS */
  }
  /* Check CRS SYNCWARN flag  */
  if ((it_flags_sources & LL_CRS_ISR_SYNCWARNF) != 0U)
  {
    LL_CRS_ClearFlag_SYNCWARN(p_crsx);

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
    hcrs->p_sync_warn_cb(hcrs);
#else
    HAL_CRS_SyncWarnCallback(hcrs);
#endif /* USE_HAL_CRS_REGISTER_CALLBACKS */
  }
  /* Check CRS Expected SYNC flag */
  if ((it_flags_sources & LL_CRS_ISR_ESYNCF) != 0U)
  {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
    hcrs->last_error_codes = HAL_CRS_ERROR_EXPECTED_SYNC;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

    LL_CRS_ClearFlag_ESYNC(p_crsx);

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
    hcrs->p_expected_sync_cb(hcrs);
#else
    HAL_CRS_ExpectedSyncCallback(hcrs);
#endif /* USE_HAL_CRS_REGISTER_CALLBACKS */
  }
  /* Check CRS Error flags */
  if ((it_flags_sources & LL_CRS_ISR_ERRF) != 0U)
  {

    if ((LL_CRS_IsActiveFlag_SYNCERR(p_crsx)) != 0U)
    {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
      hcrs->last_error_codes = HAL_CRS_ERROR_SYNC_ERROR;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
    }
    else if ((LL_CRS_IsActiveFlag_SYNCMISS(p_crsx)) != 0U)
    {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
      hcrs->last_error_codes = HAL_CRS_ERROR_SYNC_MISSED;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
    }
    else /* Trimming overflow or underflow flag set */
    {
#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
      hcrs->last_error_codes = HAL_CRS_ERROR_TRIMMING;
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */
    }

    LL_CRS_ClearFlag_ERR(p_crsx);

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
    hcrs->p_error_cb(hcrs);
#else
    HAL_CRS_ErrorCallback(hcrs);
#endif /* USE_HAL_CRS_REGISTER_CALLBACKS */
  }
}

/**
  * @brief  Clock Recovery System SYNCOK interrupt callback.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function must not be modified in this file, but must preferably be implemented in the user file.
  */
__WEAK void HAL_CRS_SyncOkCallback(hal_crs_handle_t *hcrs)
{
  STM32_UNUSED(hcrs);
}

/**
  * @brief  Clock Recovery System SYNCWARN interrupt callback.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function must not be modified in this file, but must preferably be implemented in the user file.
  */
__WEAK void HAL_CRS_SyncWarnCallback(hal_crs_handle_t *hcrs)
{
  STM32_UNUSED(hcrs);
}

/**
  * @brief  Clock Recovery System Expected SYNC interrupt callback.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function must not be modified in this file, but must preferably be implemented in the user file.
  */
__WEAK void HAL_CRS_ExpectedSyncCallback(hal_crs_handle_t *hcrs)
{
  STM32_UNUSED(hcrs);
}

/**
  * @brief  Clock Recovery System Error interrupt callback.
  * @param  hcrs Pointer to a hal_crs_handle_t structure that contains
  *              the handle information for the specified CRS instance.
  * @note   This function must not be modified in this file, but must preferably be implemented in the user file.
  */
__WEAK void HAL_CRS_ErrorCallback(hal_crs_handle_t *hcrs)
{
  STM32_UNUSED(hcrs);
}

#if defined(USE_HAL_CRS_REGISTER_CALLBACKS) && (USE_HAL_CRS_REGISTER_CALLBACKS == 1U)
/**
  * @brief  Register a User CRS callback for synchronization ok.
  * @param  hcrs Pointer to the CRS handle.
  * @param  p_callback Pointer to the synchronization ok callback function.
  * @retval HAL_OK  Register completed successfully.
  * @retval HAL_INVALID_PARAM p_callback pointer is NULL.
  */
hal_status_t HAL_CRS_RegisterSyncOkCallback(hal_crs_handle_t *hcrs, hal_crs_cb_t p_callback)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_callback != NULL);

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the p_callback pointer */
  if (p_callback == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  hcrs->p_sync_ok_cb = p_callback;
  return HAL_OK;
}

/**
  * @brief  Register a User CRS callback for synchronization warning.
  * @param  hcrs Pointer to the CRS handle.
  * @param  p_callback Pointer to the synchronization warning callback function.
  * @retval HAL_OK  Register completed successfully.
  * @retval HAL_INVALID_PARAM p_callback pointer is NULL.
  */
hal_status_t HAL_CRS_RegisterSyncWarnCallback(hal_crs_handle_t *hcrs, hal_crs_cb_t p_callback)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_callback != NULL);

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the p_callback pointer */
  if (p_callback == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  hcrs->p_sync_warn_cb = p_callback;
  return HAL_OK;
}

/**
  * @brief  Register a User CRS callback for expected synchronization.
  * @param  hcrs Pointer to the CRS handle.
  * @param  p_callback Pointer to the expected synchronization callback function.
  * @retval HAL_OK  Register completed successfully.
  * @retval HAL_INVALID_PARAM p_callback pointer is NULL.
  */
hal_status_t HAL_CRS_RegisterExpectedSyncCallback(hal_crs_handle_t *hcrs, hal_crs_cb_t p_callback)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_callback != NULL);

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the p_callback pointer */
  if (p_callback == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  hcrs->p_expected_sync_cb = p_callback;
  return HAL_OK;
}

/**
  * @brief  Register a User CRS callback for error.
  * @param  hcrs Pointer to the CRS handle.
  * @param  p_callback Pointer to the error callback function.
  * @retval HAL_OK  Register completed successfully.
  * @retval HAL_INVALID_PARAM p_callback pointer is NULL.
  */
hal_status_t HAL_CRS_RegisterErrorCallback(hal_crs_handle_t *hcrs, hal_crs_cb_t p_callback)
{
  ASSERT_DBG_PARAM(hcrs != NULL);
  ASSERT_DBG_PARAM(p_callback != NULL);

#if defined(USE_HAL_CHECK_PARAM) && (USE_HAL_CHECK_PARAM == 1U)
  /* Check the p_callback pointer */
  if (p_callback == NULL)
  {
    return HAL_INVALID_PARAM;
  }
#endif /* USE_HAL_CHECK_PARAM */

  ASSERT_DBG_STATE(hcrs->global_state, (uint32_t)HAL_CRS_STATE_IDLE | (uint32_t)HAL_CRS_STATE_ACTIVE);

  hcrs->p_error_cb = p_callback;
  return HAL_OK;
}
#endif  /* USE_HAL_CRS_REGISTER_CALLBACKS */

/**
  * @}
  */

/** @addtogroup CRS_Exported_Functions_Group6
  * @{
This section permits to get in runtime the state of the peripheral CRS with HAL_CRS_GetState().
  */
/**
  * @brief  Get the CRS state.
  * @param  hcrs Pointer to the CRS handle.
  * @retval hal_crs_state_t HAL CRS state.
  */
hal_crs_state_t HAL_CRS_GetState(const hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  return hcrs->global_state;
}

/**
  * @}
  */

#if defined(USE_HAL_CRS_GET_LAST_ERRORS) && (USE_HAL_CRS_GET_LAST_ERRORS == 1U)
/** @addtogroup CRS_Exported_Functions_Group7
  * @{
This section permits to get in runtime the last error codes of the peripheral CRS with HAL_CRS_GetLastErrorCodes().
  */

/**
  * @brief  Get the CRS last error codes.
  * @param  hcrs Pointer to the CRS handle.
  * @retval uint32_t This return value can be a combination of the following values:
  *         @arg @ref HAL_CRS_ERROR_NONE
  *         @arg @ref HAL_CRS_ERROR_SYNC_ERROR
  *         @arg @ref HAL_CRS_ERROR_SYNC_MISSED
  *         @arg @ref HAL_CRS_ERROR_TRIMMING
  *         @arg @ref HAL_CRS_ERROR_EXPECTED_SYNC
  *         @arg @ref HAL_CRS_ERROR_SYNC_WARN
  */
uint32_t HAL_CRS_GetLastErrorCodes(const hal_crs_handle_t *hcrs)
{
  ASSERT_DBG_PARAM(hcrs != NULL);

  return hcrs->last_error_codes;
}

/**
  * @}
  */
#endif /* USE_HAL_CRS_GET_LAST_ERRORS */

#if defined(USE_HAL_CRS_USER_DATA) && (USE_HAL_CRS_USER_DATA == 1U)
/** @addtogroup CRS_Exported_Functions_Group8
  * @{
This section provides functions allowing to Set and Get user data:
- HAL_CRS_SetUserData() to store the user data into the CRS handle.
- HAL_CRS_GetUserData() to retrieve the user data from the CRS handle.
  */

/**
  * @brief Store the user data into the CRS handle.
  * @param hcrs        Pointer to CRS handle.
  * @param p_user_data Pointer to the user data.
  */
void HAL_CRS_SetUserData(hal_crs_handle_t *hcrs, const void *p_user_data)
{
  /* Check the CRS handle allocation */
  ASSERT_DBG_PARAM(hcrs != NULL);

  /* Set user data */
  hcrs->p_user_data = p_user_data;
}

/**
  * @brief  Retrieve the user data from the CRS handle.
  * @param  hcrs Pointer to CRS handle.
  * @retval Pointer to the user data.
  */
const void *HAL_CRS_GetUserData(const hal_crs_handle_t *hcrs)
{
  /* Check the CRS handle allocation */
  ASSERT_DBG_PARAM(hcrs != NULL);

  return (hcrs->p_user_data);
}
/**
  * @}
  */
#endif /* USE_HAL_CRS_USER_DATA */

/**
  * @}
  */

/**
  * @}
  */
#endif /* USE_HAL_CRS_MODULE */
#endif /* CRS */

/**
  * @}
  */
