/**
 ******************************************************************************
 * @file    stm32_seq.h
 * @author  MCD Application Team
 * @brief   sequencer interface
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * 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.
 *
 ******************************************************************************
 */


/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_SEQ_H
#define STM32_SEQ_H

#ifdef __cplusplus
extern "C" {
#endif

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

/** @defgroup SEQUENCER sequencer utilities
  * @{
  */

/* Exported types ------------------------------------------------------------*/
/** @defgroup SEQUENCER_Exported_type SEQUENCER exported types
 *  @{
 */
/**
 *  @brief  bit mapping of the task.
 *  this value is used to represent a list of task (each corresponds to a task).
 */

typedef uint32_t UTIL_SEQ_bm_t;

/**
  * @}
 */

/* Exported constants --------------------------------------------------------*/

/** @defgroup SEQUENCER_Exported_const SEQUENCER exported constants
 *  @{
 */

/**
 * @brief This provides a default value for unused parameter
 *
 */
#define UTIL_SEQ_RFU 0

/**
 * @brief Default value used to start the scheduling.
 *
 * This informs the sequencer that all tasks registered shall be considered
 *
 * @note
 * This should be used in the application\n
 * while(1)\n
 * {\n
 *    UTIL_SEQ_Run( UTIL_SEQ_DEFAULT );\n
 * }\n
 *
 */
#define UTIL_SEQ_DEFAULT         (~0U)

/**
  * @}
 */

/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/

/** @defgroup SEQUENCER_Exported_macro SEQUENCER exported macros
 *  @{
 */

/**
 * @brief  This macro can be used to define a task with one parameter
 *
 * @note   this is an example of using this macro
 *
 *         task prototype definition
 *         void FUNCTION_NAME(void *Instance)
 *         {
 *             uint8_t _instance = *(uint8_t*) Instance;
 *         }
 *
 *         task declaration in the application for two instances
 *         const uint8_t instance1 = 1;
 *         const uint8_t instance2 = 2;
 *         UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance1)
 *         UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance2)
 *
 *         task initialization
 *         UTIL_SEQ_RegTask(1 << 1,  0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance2));
 *         UTIL_SEQ_RegTask(1 << 10, 0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance3));
 *
 *         Then no change on the management of the task within the application, the instance being managed within the overloaded function
 *
 */
#define UTIL_SEQ_TaskParamDef(_FUNC_,_PARAM_VAL_)                \
         static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void);       \
         static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void)        \
         {                                                       \
           static void *SEQ_PARAM_##_FUNC_ = (void*)&_PARAM_VAL_;\
           _FUNC_(SEQ_PARAM_##_FUNC_);                           \
         }

/**
 * @brief  This macro is used to retrieve the function name of the task
 */
#define UTIL_SEQ_TaskFunction(_FUNC_,_PARAM_VAL_)  SEQ_FUNC_##_FUNC_##_PARAM_VAL_

/**
  * @}
 */

/* Exported functions ------------------------------------------------------- */

/** @defgroup SEQUENCER_Exported_function SEQUENCER exported functions
 *  @{
 */

/**
 * @brief  This function initializes the sequencer resources.
 *
 * @note   It shall not be called from an ISR.
 *
 */
void UTIL_SEQ_Init( void );

/**
 * @brief  This function un-initializes the sequencer resources.
 *
 * @note   It shall not be called from an ISR
 *
 */
void UTIL_SEQ_DeInit( void );

/**
 * @brief This function is called by the sequencer in critical section (PRIMASK bit) when
 *          - there are no more tasks to be executed
 *          AND
 *          - there are no pending event or the pending event is still not set
 * @note  The application should enter low power mode in this function
 *        When this function is not implemented by the application, the sequencer keeps running a while loop (RUN MODE).
 *        It shall be called only by the sequencer.
 *
 */
void UTIL_SEQ_Idle( void );

/**
 * @brief This function is called by the sequencer outside critical section just before calling UTIL_SEQ_Idle( )
 *        UTIL_SEQ_PreIdle() is considered as the last task executed before calling UTIL_SEQ_Idle( )
 *        In case a task or an event is set from an interrupt handler just after UTIL_SEQ_PreIdle() is called,
 *        UTIL_SEQ_Idle() will not be called.
 *
 * @note  It shall be called only by the sequencer.
 *
 */
void UTIL_SEQ_PreIdle( void );

/**
 * @brief This function is called by the sequencer outside critical section either
 *        - after calling UTIL_SEQ_Idle( )
 *        OR
 *        - after calling UTIL_SEQ_PreIdle( ) without call to UTIL_SEQ_Idle() due to an incoming task set or event
 *          requested after UTIL_SEQ_PreIdle() has been called.
 *
 * @note  UTIL_SEQ_PostIdle() is always called if UTIL_SEQ_PreIdle() has been called and never called otherwise.
 *        It shall be called only by the sequencer.
 *
 */
void UTIL_SEQ_PostIdle( void );

/**
 * @brief This function requests the sequencer to execute all pending tasks using round robin mechanism.
 *        When no task are pending, it calls UTIL_SEQ_Idle();
 *        This function should be called in a while loop in the application
 *
 * @param Mask_bm list of task (bit mapping) that is be kept in the sequencer list.
 *
 * @note  It shall not be called from an ISR.
 * @note  The construction of the task must take into account the fact that there is no counting / protection
 *        on the activation of the task. Thus, when the task is running, it must perform all the operations
 *        in progress programmed before its call or manage a reprogramming of the task.
 *
 */
void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm );

/**
 * @brief This function registers a task in the sequencer.
 *
 * @param TaskId_bm The Id of the task
 * @param Flags Flags are reserved param for future use
 * @param Task Reference of the function to be executed
 *
 * @note  It may be called from an ISR.
 *
 */
void UTIL_SEQ_RegTask( UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void ) );

/**
 * @brief This function requests a task to be executed
 *
 * @param TaskId_bm The Id of the task
 *        It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
 * @param Task_Prio The priority of the task
 *        It shall a number from  0 (high priority) to 31 (low priority)
 *        The priority is checked each time the sequencer needs to select a new task to execute
 *        It does not permit to preempt a running task with lower priority
 *
 * @note   It may be called from an ISR
 *
 */
void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm , uint32_t Task_Prio );

/**
 * @brief This function checks if a task could be scheduled.
 *
 * @param TaskId_bm The Id of the task
 *        It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
 * @retval 0 if not 1 if true
 *
 * @note   It may be called from an ISR.
 *
 */
uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm);

/**
 * @brief This function prevents a task to be called by the sequencer even when set with UTIL_SEQ_SetTask()
 *        By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask()
 *        When a task is paused, it is moved out from the sequencer list
 *
 * @param TaskId_bm The Id of the task
 *        It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
 *
 * @note  It may be called from an ISR.
 *
 */
void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm );

/**
 * @brief This function allows to know if the task has been put in pause.
 *        By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask()
 *        The exit of the pause shall be done by the function UTIL_SEQ_ResumeTask.
 *
 * @param TaskId_bm The Id of the task
 *        It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
 *
 * @note  It may be called from an ISR.
 *
 */
uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm );

/**
 * @brief This function allows again a task to be called by the sequencer if set with UTIL_SEQ_SetTask()
 *        This is used in relation with UTIL_SEQ_PauseTask()
 *
 * @param TaskId_bm The Id of the task
 *        It shall be (1<<task_id) where task_id is the number assigned when the task has been registered
 *
 * @note  It may be called from an ISR.
 *
 */
void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm );

/**
 * @brief This function sets an event that is waited with UTIL_SEQ_WaitEvt()
 *
 * @param EvtId_bm event id bit mask
 *
 * @note  An event shall be a 32 bit mapping where only 1 bit is set
 *        It may be called from an ISR.
 *
 */
void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm );

/**
 * @brief This function may be used to clear the event before calling UTIL_SEQ_WaitEvt()
 *        This API may be useful when the UTIL_SEQ_SetEvt() is called several time to notify the same event.
 *        Due to Software Architecture where the timings are hard to control, this may be an unwanted case.
 *
 * @param EvtId_bm event id bm
 *        It shall be a bit mapping where only 1 bit is set
 *
 * @note   It may be called from an ISR.
 *
 */
void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm );

/**
 * @brief This function waits for a specific event to be set. The sequencer loops UTIL_SEQ_EvtIdle() until the event is set
 *        When called recursively, it acts as a First in / Last out mechanism. The sequencer waits for the
 *        last event requested to be set even though one of the already requested event has been set.
 *
 * @param EvtId_bm event id bit mask
 *        It shall be a bit mapping where only 1 bit is set
 *
 * @note  It shall not be called from an ISR.
 * @note  The construction of the task must take into account the fact that there is no counting / protection on the
 *        event. Thus, when the task is running, it must perform all the operations in progress programmed before its call
 *        or manage a reprogramming of the task.
 */
void UTIL_SEQ_WaitEvt( UTIL_SEQ_bm_t EvtId_bm );

/**
 * @brief This function returns whether the waited event is pending or not
 *        It is useful only when the UTIL_SEQ_EvtIdle() is overloaded by the application. In that case, when the low
 *        power mode needs to be executed, the application shall first check whether the waited event is pending
 *        or not. Both the event checking and the low power mode processing should be done in critical section
 *
 * @retval 0 when the waited event is not there or the evt_id when the waited event is pending
 *
 * @note   It may be called from an ISR.
 *
 */
UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void );

/**
 * @brief This function loops until the waited event is set
 * @param TaskId_bm The task id that is currently running. When task_id_bm = 0, it means UTIL_SEQ_WaitEvt( )
 *                     has been called outside a registered task (ie at startup before UTIL_SEQ_Run( ) has been called
 * @param EvtWaited_bm The event id that is waited.
 *
 * @note  When not implemented by the application, it calls UTIL_SEQ_Run(~TaskId_bm) which means the waited
 *        task is suspended until the waited event and the other tasks are running or the application enter
 *        low power mode.
 *        Else the user can redefine his own function for example call sequencer UTIL_SEQ_Run(0) to suspend all
 *        the task and let the sequencer enter the low power mode.
 *        It shall be called only by the sequencer.
 *
 */
void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm );

/**
  * @}
 */

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /*__STM32_SEQ_H */

