/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
//  ==== Kernel Control ====
/** 
\addtogroup CMSIS_RTOS_KernelCtrl Kernel Information and Control
\ingroup CMSIS_RTOS
\brief Provides version/system information and starts/controls the RTOS Kernel.
\details 
The kernel Information and Control function group allows to:
  - obtain information about the system and the underlying kernel.
  - obtain version information about the CMSIS-RTOS API.
  - initialize of the RTOS kernel for creating objects.
  - start the RTOS kernel and thread switching.
  - check the execution status of the RTOS kernel.

\note The kernel information and control functions cannot be called from
\ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".
\note The kernel initialization is documented in \ref SystemStartup.

<b>Code Example</b>
\code
/*----------------------------------------------------------------------------
 * Application main thread
 *---------------------------------------------------------------------------*/
void app_main (void *argument) {
 
  // ...
  for (;;) {}
}
 
int main (void) {
 
  // System Initialization
  SystemCoreClockUpdate();
  // ...
 
  osKernelInitialize();                 // Initialize CMSIS-RTOS
  osThreadNew(app_main, NULL, NULL);    // Create application main thread
  osKernelStart();                      // Start thread execution
  for (;;) {}
}
\endcode
@{
*/
/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\struct osVersion_t
\details
Identifies the underlying RTOS kernel and API version number. The version is represented in a combined decimal number in the
format: major.minor.rev: mmnnnrrrr 

Use \ref osKernelGetInfo to retrieve the version numbers.
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\typedef osKernelState_t
\details
State of the kernel as retrieved by \ref osKernelGetState. In case \b osKernelGetState fails or if it is called from an ISR,
it will return \c osKernelError, otherwise it returns the kernel state.

\var osKernelState_t::osKernelInactive
\details
The kernel is not ready yet. \ref osKernelInitialize needs to be executed successfully.

\var osKernelState_t::osKernelReady
\details
The kernel is not yet running. \ref osKernelStart transfers the kernel to the running state.

\var osKernelState_t::osKernelRunning
\details
The kernel is initialized and running.

\var osKernelState_t::osKernelLocked
\details
The kernel was locked with \ref osKernelLock. The functions \ref osKernelUnlock or \ref osKernelRestoreLock unlocks it.

\var osKernelState_t::osKernelSuspended
\details
The kernel was suspended using \ref osKernelSuspend. The function \ref osKernelResume returns to normal operation.

\var osKernelState_t::osKernelError
\details
An error occurred.

\var osKernelState_t::osKernelReserved
\details
Reserved.

*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osStatus_t osKernelInitialize (void)
\details
The function \b osKernelInitialize initializes the RTOS Kernel. Before it is successfully executed, only the functions
\ref osKernelGetInfo and \ref osKernelGetState may be called.
 
Possible \ref osStatus_t return values:
- \em osOK in case of success.
- \em osError if an unspecific error occurred.
- \em osErrorISR if called from an \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routine".
- \em osErrorNoMemory if no memory could be reserved for the operation.

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b> Code Example</b>
\code
#include "RTE_Components.h"
#include  CMSIS_device_header
#include "cmsis_os2.h"
 
/*----------------------------------------------------------------------------
 * Application main thread
 *---------------------------------------------------------------------------*/
void app_main (void *argument) {
 
  // ...
  for (;;) {}
}
 
int main (void) {
 
  // System Initialization
  SystemCoreClockUpdate();
  // ...
 
  osKernelInitialize();                 // Initialize CMSIS-RTOS
  osThreadNew(app_main, NULL, NULL);    // Create application main thread
  osKernelStart();                      // Start thread execution
  for (;;) {}
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size)
\details
The function \b  osKernelGetInfo retrieves the API and kernel version of the underlying RTOS kernel and a human readable
identifier string for the kernel. It can be safely called before the RTOS is initialized or started (call to
\ref osKernelInitialize or \ref osKernelStart).

Possible \ref osStatus_t return values:
- \em osOK in case of success.
- \em osError if an unspecific error occurred.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
void info (void) {
  char infobuf[100];
  osVersion_t osv;
  osStatus_t status;
 
  status = osKernelGetInfo(&osv, infobuf, sizeof(infobuf));
  if(status == osOK) {
    printf("Kernel Information: %s\r\n", infobuf);
    printf("Kernel Version    : %d\r\n", osv.kernel);
    printf("Kernel API Version: %d\r\n", osv.api);
  }
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osKernelState_t osKernelGetState (void)
\details
The function \b osKernelGetState returns the current state of the kernel and can be safely called before the RTOS is
initialized or started (call to \ref osKernelInitialize or \ref osKernelStart). In case it fails it will return \c osKernelError,
otherwise it returns the kernel state (refer to \ref osKernelState_t for the list of kernel states).

Possible \ref osKernelState_t return values:
- \ref osKernelError if an unspecific error occurred.
- the actual kernel state otherwise.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
int main (void) {
  // System Initialization
  SystemCoreClockUpdate();
  // ...
  if(osKernelGetState() == osKernelInactive) {     // Is the kernel initialized?
     osKernelInitialize();                         // Initialize CMSIS-RTOS kernel
  }
  ;
}
\endcode

*/
/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osStatus_t osKernelStart (void)
\details
The function \b osKernelStart starts the RTOS kernel and begins thread switching. It will not return to its calling function
in case of success. Before it is successfully executed, only the functions \ref osKernelGetInfo, \ref osKernelGetState, and
object creation functions (\b osXxxNew) may be called.

At least one initial thread should be created prior osKernelStart, see \ref osThreadNew.

Possible \ref osStatus_t return values:
- \em osError if an unspecific error occurred.
- \em osErrorISR if called from an \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routine".
 
\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
int main (void) {
  // System Initialization
  SystemCoreClockUpdate();
  // ...
  if(osKernelGetState() == osKernelInactive) {
    osKernelInitialize();
  }
  ; // ... Start Threads
  if (osKernelGetState() == osKernelReady) {        // If kernel is ready to run...
    osKernelStart();                                // ... start thread execution
    }
  
  while(1);                                         // only reached in case of error
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn int32_t osKernelLock (void)
\details
The function \b osKernelLock allows to lock all task switches. It returns the previous value of the lock state (\token{1} if
it was locked, \token{0} if it was unlocked), or a negative number representing an error code otherwise (refer to
\ref osStatus_t).

Possible \ref osStatus_t return values:
- \em osError if an unspecific error occurred.
- \em osErrorISR if called from an \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routine".
- \em osErrorSafetyClass if the calling thread safety class is lower than the kernel protect safety class.

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
  int32_t state = osKernelLock();
  // ... critical code
  osKernelRestore(state);
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn int32_t osKernelUnlock (void)
\details
The function \b osKernelUnlock resumes from \ref osKernelLock. It returns the previous value of the lock state (\token{1} if
it was locked, \token{0} if it was unlocked), or a negative number representing an error code otherwise (refer to
\ref osStatus_t).

Possible \ref osStatus_t return values:
- \em osError if an unspecific error occurred.
- \em osErrorISR if called from an \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routine".

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
  int32_t sl = osKernelLock();
  // ... critical code
  {
    int32_t su = osKernelUnlock();
    // ... uncritical code
    osKernelRestoreLock(su);
  }
  // ... critical code
  osKernelRestoreLock(sl);
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn int32_t osKernelRestoreLock (int32_t lock)
\details
The function \b osKernelRestoreLock restores the previous lock state after \ref osKernelLock or \ref osKernelUnlock.

The argument \a lock specifies the lock state as obtained by \ref osKernelLock or \ref osKernelUnlock.

The function returns the new value of the lock state (\token{1} if it was locked, \token{0} if it was unlocked), or a
negative number representing an error code otherwise (refer to \ref osStatus_t).

Possible \ref osStatus_t return values:
- \em osError if an unspecific error occurred.
- \em osErrorISR if called from interrupt other than fault or \ref osWatchdogAlarm_Handler.
- \em osErrorSafetyClass if the calling thread safety class is lower than the kernel protect safety class.

<b>Code Example</b>
\code
  int32_t sl = osKernelLock();
  // ... critical code
  {
    int32_t su = osKernelUnlock();
    // ... uncritical code
    osKernelRestoreLock(su);
  }
  // ... critical code
  osKernelRestoreLock(sl);
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn uint32_t osKernelSuspend (void)
\details
CMSIS-RTOS2 provides extension for tick-less operation which is useful for applications that use extensively low-power modes where the SysTick timer is also disabled.

To provide a time-tick in such power-saving modes a wake-up timer is used to derive timer intervals. The function \b osKernelSuspend suspends the RTOS kernel scheduler and thus enables sleep modes.

The return value can be used to determine the amount of system ticks until the next tick-based kernel event will occur, i.e. a delayed thread becomes ready again. It is recommended to set up the low power timer to generate a wake-up interrupt based on this return value.

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
void osRtxIdleThread (void) {
                                               /* The idle thread is running
                                                  when no other thread is ready
                                                  to run.                      */
  unsigned int sleep;
 
  for (;;) {
                                               /* HERE: include optional user
                                                  code to be executed when no
                                                  task runs.                   */
    sleep = osKernelSuspend();                 /* Suspend RTOS kernel scheduler */
 
    if (sleep) {                               /* How long can we sleep?       */
                                               /* "sleep" is in kernel Timer Ticks
                                                  which is 1ms in this
                                                  configuration                */
       
                                               /* Setup wake-up e.g. watchdog  */
 
      __WFE();                                 /* Enter Power-down mode        */
      
                                               /* After Wake-up                */
      sleep = tc;                              /* Adjust with cycles slept     */  
    }
 
    osKernelResume(sleep);                     /* Resume thread scheduler      */
  }
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn void osKernelResume (uint32_t sleep_ticks)
\details
CMSIS-RTOS provides extension for tick-less operation which is useful for applications that use extensively low-power modes where the SysTick timer is also disabled. 

To provide a time-tick in such power-saving modes a wake-up timer is used to derive timer intervals. The function \b osKernelResume enables the RTOS kernel scheduler and thus wakes up the system from sleep
mode.

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code
void osRtxIdleThread (void) {
                                               /* The idle thread is running
                                                  when no other thread is ready
                                                  to run.                      */
  unsigned int sleep;
 
  for (;;) {
                                               /* HERE: include optional user
                                                  code to be executed when no
                                                  task runs.                   */
    sleep = osKernelSuspend();                 /* Suspend RTOS kernel scheduler */
 
    if (sleep) {                               /* How long can we sleep?       */
                                               /* "sleep" is in Kernel Timer Ticks
                                                  which is 1ms in this
                                                  configuration                */
       
                                               /* Setup wake-up e.g. watchdog  */
 
      __WFE();                                 /* Enter Power-down mode        */
      
                                               /* After Wake-up                */
      sleep = tc;                              /* Adjust with cycles slept     */  
    }
 
    osKernelResume(sleep);                     /* Resume thread scheduler      */
  }
}
\endcode

*/
/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn uint32_t osKernelGetTickCount (void)
\details
The function \b osKernelGetTickCount returns the current RTOS kernel tick count.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

\b Code \b Example
\code
#include "cmsis_os2.h"
 
void Thread_1 (void *arg)  {                // Thread function
  uint32_t tick;

  tick = osKernelGetTickCount();            // retrieve the number of system ticks
  for (;;) {
    tick += 1000;                           // delay 1000 ticks periodically
    osDelayUntil(tick);
    // ...
  }
}\endcode

Due to the limited value range used for the tick count it may overflow during runtime,
i.e. after 2<sup>32</sup> ticks which are roughly 49days @ 1ms. Typically one has not to
take special care of this unless a monotonic counter is needed. For such a case an additional
64bit tick counter can be implemented as follows. The given example needs GetTick() called at
least twice per tick overflow to work properly.

\b Code \b Example
\code
uint64_t GetTick(void) {
  static uint32_t tick_h = 0U;
  static uint32_t tick_l = 0U;
         uint32_t tick;

  tick = osKernelGetTickCount();
  if (tick < tick_l) {
    tick_h++;
  }
  tick_l = tick;

  return (((uint64_t)tick_h << 32) | tick_l);
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn uint32_t osKernelGetTickFreq (void)
\details
The function \b osKernelGetTickFreq returns the frequency of the current RTOS kernel tick.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn uint32_t osKernelGetSysTimerCount (void)
\details
The function \b osKernelGetSysTimerCount returns the current RTOS kernel system timer as a 32-bit value. 
The value is a rolling 32-bit counter that is composed of the kernel system interrupt timer value
and the counter that counts these interrupts (RTOS kernel ticks).

This function allows the implementation of very short timeout checks below the RTOS tick granularity.
Such checks might be required when checking for a busy status in a device or peripheral initialization
routine, see code example below.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example</b>
\code{.c}
#include "cmsis_os2.h"
 
void SetupDevice (void)  {
  uint32_t tick;
  
  // Calculating 100us timeout in system timer ticks
  const uint32_t timeout = 100U * osKernelGetSysTimerFreq() / 1000000u;
  
  tick = osKernelGetSysTimerCount();             // get start value of the Kernel system tick
  Device.Setup ();                               // initialize a device or peripheral
  do {                                           // poll device busy status for 100 microseconds
    if (!Device.Busy) break;                     // check if device is correctly initialized
  } while ((osKernelGetSysTimerCount() - tick) < timeout));
  if (Device.Busy)  {              
    ;                                            // in case device still busy, signal error
  }
                                                 // start interacting with device
}

\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn uint32_t osKernelGetSysTimerFreq (void)
\details
The function \b osKernelGetSysTimerFreq returns the frequency of the current RTOS kernel system timer.

\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osStatus_t osKernelProtect (uint32_t safety_class);
\details
The function \b osKernelProtect configures kernel access protection. After its successful execution, only threads with
safety class equal or higher than the \a safety_class specified in the argument can execute kernel control functions.
- \ref osKernelLock
- \ref osKernelUnlock
- \ref osKernelRestoreLock
- \ref osKernelSuspend
- \ref osKernelResume
- \ref osKernelProtect

Possible \ref osStatus_t return values:
- \em osOK in case of success.
- \em osErrorParameter if \a safety_class is invalid.
- \em osError if kernel is not in ready or running state.
- \em osErrorISR if called from an \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routine".
- \em osErrorSafetyClass if the calling thread safety class is lower than the kernel protect safety class.

\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".

<b>Code Example:</b>
\code
#include "cmsis_os2.h"
 
void ProtectKernelControlFunctions (void) {
  osStatus_t status;
 
  status = osKernelProtect(4U); // Enable Kernel Control for threads with safety class 4 or higher
  // verify status value here.
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn osStatus_t osKernelDestroyClass (uint32_t safety_class, uint32_t mode);
\details
The function \b osKernelDestroyClass destroys RTOS objects based on safety class assignment. \a safety_class provides the reference safety class value, while \a mode is considered as a bitmap that additionally specifies the safety classes to be destroyed.

If \ref osSafetyWithSameClass is set in \a mode than the RTOS objects with safety class value equal to \a safety_class will be destroyed.
<br>
If \ref osSafetyWithLowerClass is set in \a mode than the RTOS objects with safety class value lower than \a safety_class will be destroyed.

Possible \ref osStatus_t return values:
- \em osOK in case of success.
- \em osErrorParameter if \a safety_class is invalid.
- \em osErrorResource if no other \ref ThreadStates "READY" thread exists.
- \em osErrorISR if called from interrupt other than \ref osWatchdogAlarm_Handler.
- \em osErrorSafetyClass if the calling thread safety class is lower than the kernel protect safety class.

<b>Code Example:</b>
\code
#include "cmsis_os2.h"
 
void DestroyNonCriticalClasses (void) {
  osStatus_t status;
 
  status = osKernelDestroyClass(4U, osSafetyWithSameClass | osSafetyWithLowerClass); // Destroy objects with safety class 4 or lower
  // verify status value here.
}
\endcode
*/

/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
/**
\fn void osFaultResume (void);
\details
Resume normal RTOS operation when exiting exception faults.

<b>Code Example:</b>
\code
void HardFault_Handler (void) {
  __ASM volatile (
    "...                          \n\t" // Enter assembly and handle faults
    "...                          \n\t"
    "ldr  r0,=osFaultResume       \n\t" // Before exiting the handler load and
    "bx   r0                      \n\t" // jump to osFaultResume
  );
}
\endcode
*/

/// @}
