CMSIS RTOS -- embOS segger

#ifndef __CMSIS_OS_H__
#define __CMSIS_OS_H__

#include <stdint.h>
#include <stddef.h>

#include "RTOS.h"

// API version (main [31:16] .sub [15:0])
#define osCMSIS               0x10002
// RTOS identification and version (main [31:16] .sub [15:0])
#define osCMSIS_RTX           ((4<<16)|00)
// RTOS identification string
#define osKernelSystemId      "EMBOS V4.00"
//
// main thread      1=main can be thread, 0=not available
#define osFeature_MainThread  1
//
// Memory Pools:    1=available, 0=not available
#define osFeature_Pool        1
//
// Mail Queues:     1=available, 0=not available
#define osFeature_MailQ       1
//
// Message Queues:  1=available, 0=not available
#define osFeature_MessageQ    1
//
// maximum number of Signal Flags available per thread
// bit31 = 0x80000000 : incorrect parameters
#define osFeature_Signals     31
//
// maximum count for osSemaphoreCreate function
#define osFeature_Semaphore   0xFFFFFFFF
//
// osWait function: 1=available, 0=not available
#define osFeature_Wait        0
//
// osKernelSysTick functions: 1=available, 0=not available
#define osFeature_SysTick     1
//
//
//
#ifdef  __cplusplus
extern "C"
{
#endif

// ==== Enumeration, structures, defines =======================================
//
// Priority used for thread control.
// MUST REMAIN UNCHANGED: osPriority shall be consistent in every CMSIS-RTOS.
//
typedef enum
{
  osPriorityIdle = -3,            // priority: idle (lowest)
  osPriorityLow = -2,             // priority: low
  osPriorityBelowNormal = -1,     // priority: below normal
  osPriorityNormal = 0,           // priority: normal (default)
  osPriorityAboveNormal = +1,     // priority: above normal
  osPriorityHigh = +2,            // priority: high
  osPriorityRealtime = +3,        // priority: realtime (highest)
  osPriorityError = 0x84          // system cannot determine priority
} osPriority;                     // or thread has illegal priority

// Timeout value.
// MUST REMAIN UNCHANGED: osWaitForever shall be consistent in every CMSIS-RTOS.
//
#define osWaitForever     0xFFFFFFFF     // wait forever timeout value
// Status code values returned by CMSIS-RTOS functions.
// MUST REMAIN UNCHANGED: osStatus shall be consistent in every CMSIS-RTOS.
//
typedef enum
{
  // function completed; no error or event occurred.
  osOK = 0,
  //
  // function completed; signal event occurred.
  osEventSignal = 0x08,
  // function completed; message event occurred.
  osEventMessage = 0x10,
  // function completed; mail event occurred.
  osEventMail = 0x20,
  //
  // function completed; timeout occurred.
  osEventTimeout = 0x40,
  //
  // parameter error: a mandatory parameter was missing or specified an incorrect object.
  osErrorParameter = 0x80,
  //
  // resource not available: a specified resource was not available.
  osErrorResource = 0x81,
  // resource not available within given time: a specified resource was not available within the timeout period.
  osErrorTimeoutResource = 0xC1,
  // not allowed in ISR context: the function cannot be called from interrupt service routines.
  osErrorISR = 0x82,
  // function called multiple times from ISR with same object.
  osErrorISRRecursive = 0x83,
  // system cannot determine priority or thread has illegal priority.
  osErrorPriority = 0x84,
  // system is out of memory: it was impossible to allocate or reserve memory for the operation.
  osErrorNoMemory = 0x85,
  // value of a parameter is out of range.
  osErrorValue = 0x86,
  // unspecified RTOS error: run-time error but no other error message fits.
  osErrorOS = 0xFF,
  //
  os_status_reserved = 0x7FFFFFFF
// prevent from enum down-size compiler optimization.
// 32 bits for osStatus
} osStatus;

// Timer type value for the timer definition.
// MUST REMAIN UNCHANGED: os_timer_type shall be consistent in every CMSIS-RTOS.
//
typedef enum
{
  osTimerOnce = 0,            // one-shot timer
  osTimerPeriodic = 1         // repeating timer --- EMBOS can not support !
} os_timer_type;

typedef struct _CMSIS_OS_GLOBAL
{
  uint32_t dummy;
} CMSIS_OS_GLOBAL;

extern CMSIS_OS_GLOBAL os_global;

// Entry point of a thread.
// MUST REMAIN UNCHANGED: os_pthread shall be consistent in every CMSIS-RTOS.
//
typedef void (*os_pthread)( void * argument );

// Entry point of a timer call back function.
// MUST REMAIN UNCHANGED: os_ptimer shall be consistent in every CMSIS-RTOS.
//
typedef void (*os_ptimer)( void * argument );

// >>> the following data type definitions may shall adapted towards a specific RTOS

// Thread ID identifies the thread (pointer to a thread control block).
// CAN BE CHANGED: os_thread_cb is implementation specific in every CMSIS-RTOS.
//
typedef OS_TASK osThreadType;
typedef osThreadType * osThreadId;

// Timer ID identifies the timer (pointer to a timer control block).
// CAN BE CHANGED: os_timer_cb is implementation specific in every CMSIS-RTOS.
//
typedef OS_TIMER_EX osTimerType;
typedef osTimerType * osTimerId;

// Mutex ID identifies the mutex (pointer to a mutex control block).
// CAN BE CHANGED: os_mutex_cb is implementation specific in every CMSIS-RTOS.
//
typedef OS_RSEMA osMutexType;
typedef osMutexType * osMutexId;

// Semaphore ID identifies the semaphore (pointer to a semaphore control block).
// CAN BE CHANGED: os_semaphore_cb is implementation specific in every CMSIS-RTOS.
//
typedef OS_CSEMA osSemaphoreType;
typedef osSemaphoreType * osSemaphoreId;

// Pool ID identifies the memory pool (pointer to a memory pool control block).
// CAN BE CHANGED: os_pool_cb is implementation specific in every CMSIS-RTOS.
//
typedef OS_MEMF osPoolType;
typedef osPoolType * osPoolId;

// Message ID identifies the message queue (pointer to a message queue control block).
// CAN BE CHANGED: os_messageQ_cb is implementation specific in every CMSIS-RTOS.
//
// OS_MAILBOX : Messages of fixed size
// CMSIS_OS   : Messages of fixed size : 4 Bytes for Value or Pointer
//
typedef OS_MAILBOX osMessageQType;
typedef osMessageQType * osMessageQId;

// Mail ID identifies the mail queue (pointer to a mail queue control block).
// CAN BE CHANGED: os_mailQ_cb is implementation specific in every CMSIS-RTOS.
//
// OS_MAILBOX : Messages of fixed size
// CMSIS_OS   : Messages of fixed size : 1..32767 Bytes for Buffer
//
typedef struct _osMailQ_cb
{
  osMessageQId messageId;
  osPoolId poolId;
} osMailQType;

typedef osMailQType * osMailQId;

// Thread Definition structure contains startup information of a thread.
// CAN BE CHANGED: os_thread_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_thread_def
{
  osThreadId threadId;
  uint8_t * name;
  os_pthread pthread;     // start address of thread function
  osPriority tpriority;   // initial thread priority
  uint32_t stacksize;     // stack size requirements in bytes;
  uint32_t * stack;       //
} osThreadDef_t;

// Timer Definition structure contains timer parameters.
// CAN BE CHANGED: os_timer_def is implementation specific in every CMSIS-RTOS.
//
typedef const struct os_timer_def
{
  osTimerId timerId;
  os_ptimer ptimer;
} osTimerDef_t;

// Mutex Definition structure contains setup information for a mutex.
// CAN BE CHANGED: os_mutex_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_mutex_def
{
  osMutexId mutexId;
} osMutexDef_t;

// Semaphore Definition structure contains setup information for a semaphore.
// CAN BE CHANGED: os_semaphore_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_semaphore_def
{
  osSemaphoreId semaphoreId;
} osSemaphoreDef_t;

// Definition structure for memory block allocation.
// CAN BE CHANGED: os_pool_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_pool_def
{
  osPoolId poolId;
  uint32_t pool_sz;     // number of items (elements) in the pool
  uint32_t item_sz;     // size of an item
  void * pool;          // pointer to memory for pool
} osPoolDef_t;

// Definition structure for message queue.
// CAN BE CHANGED: os_messageQ_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_messageQ_def
{
  osMessageQId messageQId;
  uint32_t queue_sz;    // number of elements in the queue
  void * pool;          // memory array for messages
} osMessageQDef_t;

// Definition structure for mail queue.
// CAN BE CHANGED: os_mailQ_def is implementation specific in every CMSIS-RTOS.
//
typedef struct os_mailQ_def
{
  osMailQId mailId;
  osMessageQDef_t * messageQDef;
  osPoolDef_t * poolDef;
  uint32_t queue_sz;      // number of elements in the queue
  uint32_t item_sz;       // size of an item
} osMailQDef_t;

// Event structure contains detailed information about an event.
// MUST REMAIN UNCHANGED: os_event shall be consistent in every CMSIS-RTOS.
// However the struct may be extended at the end.
//
typedef struct
{
  osStatus status;     // status code: event or error information

  union
  {
    uint32_t v;         // message as 32-bit value
    void * p;           // message or mail as void pointer
    int32_t signals;    // signal flags
  } value;              // event value

  union
  {
    osMailQId mail_id;        // mail id obtained by osMailCreate
    osMessageQId message_id;  // message id obtained by osMessageCreate
  } def;                      // event definition

} osEvent;

// ======= Kernel Control Functions ============================================

// The RTOS kernel system timer frequency in Hz.
// Reflects the system timer setting and is typically defined in a configuration file.
#define osKernelSysTickFrequency                ( OS_FSYS )
// The RTOS kernel frequency in Hz.
// Reflects the system timer setting and is typically defined in a configuration file.
#define osKernelTickFrequency                   ( OS_TICK_FREQ )
//
#define osKernelTickPeriod                      ( 1 / osKernelTickFrequency )
#define osKernelTicksPerSecond                  ( osKernelTickFrequency )

#if ( osKernelTickFrequency == 1000 )
#define osKernelTicksPerMilliSec                ( 1 )
#else
#define osKernelTicksPerMilliSec                ( osKernelTickFrequency / 1000 )
#endif

//
// Convert timeout in millisec to system ticks
#if ( osKernelTickFrequency == 1000 )
#define osKernelTicksByMilliSec( millisec )     ( millisec )
#else
#define osKernelTicksByMilliSec( millisec )     ( ( millisec ) * osKernelTicksPerMilliSec )
#endif

// Convert timeout in second to system ticks
#define osKernelTicksBySecond( second )         ( ( second ) * osKernelTicksPerSecond )

// Convert kernel ticks to millisec
#if ( osKernelTickFrequency == 1000 )
#define osKernelTicks2MilliSec( ticks )         ( ticks )
#else
#define osKernelTicks2MilliSec( ticks )         ( ( ticks ) / osKernelTicksPerMilliSec )
#endif

// Convert kernel ticks to second
#define osKernelTicks2Second( ticks )           ( ( ticks ) / osKernelTicksPerSecond )
//
//
#define osKernelSysTicksPerSecond               ( osKernelSysTickFrequency )
#define osKernelSysTicksPerMilliSec             ( osKernelSysTickFrequency / 1000 )
//
// Convert timeout in millisec to system ticks
#define osKernelSysTicksByMilliSec( millisec )  ( ( millisec ) * osKernelSysTicksPerMilliSec )
// Convert timeout in second to system ticks
#define osKernelSysTicksBySecond( second )      ( ( second ) * osKernelSysTicksPerSecond )
// Convert system ticks to millisec
#define osKernelSysTicks2MilliSec( ticks )      ( ( ticks ) / osKernelSysTicksPerMilliSec )
// Convert system ticks to second
#define osKernelSysTicks2Second( ticks )        ( ( ticks ) / osKernelSysTicksPerSecond )
//

#define osKernelSysTickMicroSec_i  \
  ( osKernelSysTickFrequency / 1000000 )
//
#define osKernelSysTickMicroSec_f  \
  ( ( ( (uint64_t)( osKernelSysTickFrequency - 1000000 * ( osKernelSysTickFrequency / 1000000 ) ) ) << 16 ) / 1000000 )
//
// Convert a microseconds value to a RTOS kernel system timer value.
#define osKernelSysTickMicroSec(microsec)   \
  ( ( microsec * osKernelSysTickMicroSec_i ) + ( ( microsec * osKernelSysTickMicroSec_f ) >> 16 ) )
//
#define osKernelSysTickMilliSec(millisec)   \
  osKernelSysTicksByMilliSec(millisec)

// return RTOS kernel time as 32-bit value in milli second
//
//#include "rt_Time.h"
//#define osKernelTickTime                ( os_time / osKernelTicksPerMilliSec )
//
#define osKernelTickTime                  ( OS_Time / osKernelTicksPerMilliSec )
#define osKernelTickCount()               OS_GetTime32()
#define osKernelSysTick()                 OS_GetTime_Cycles()

osStatus osKernelInitialize( void );
osStatus osKernelStart( void );
int32_t osKernelRunning( void );

// ======= Thread Management ===================================================
//
// Create a Thread Definition with function, priority, and stack requirements.
// param         name         name of the thread function.
// param         priority     initial priority of the thread function.
// param         instances    number of possible thread instances.
// param         stacksz      stack size (in bytes) requirements for the thread function.
// CAN BE CHANGED: The parameters to osThreadDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
//
#if defined (osObjectsExternal)
#define osThreadDef(name, thread, priority, instances, stacksz)       \
  extern osThreadDef_t os_thread_def_##name
#else
#define osThreadDef(name, thread, priority, instances, stacksz)       \
  OS_TASK os_thread_id_##name;                                        \
    uint32_t os_thread_stack_##name[ ( (stacksz ? stacksz : OS_STKSIZE ) + 3 ) / 4];      \
  osThreadDef_t os_thread_def_##name =                                \
      { &os_thread_id_##name, #name, (os_pthread)(thread), (priority),\
        (( ( (stacksz ? stacksz : OS_STKSIZE ) + 3 ) / 4) << 2 ),     \
          os_thread_stack_##name }
#endif

#define osThread(name)  \
  &os_thread_def_##name

osThreadId osThreadCreate( osThreadDef_t * thread_def, void * argument );
osThreadId osThreadGetId( void );
osStatus osThreadTerminate( osThreadId thread_id );
osStatus osThreadYield( void );
osStatus osThreadSetPriority( osThreadId thread_id, osPriority priority );
osPriority osThreadGetPriority( osThreadId thread_id );

// ======= Generic Wait Functions ==============================================
//
// Wait for Timeout (Time Delay).
// param[in]     millisec      time delay value
// return status code that indicates the execution status of the function.
//
osStatus osDelay( uint32_t millisec );

#if (defined (osFeature_Wait)  &&  (osFeature_Wait != 0))
osEvent osWait( uint32_t millisec );
#endif

// ======= Timer Management Functions ==========================================
//
// Define a Timer object.
// param         name          name of the timer object.
// param         function      name of the timer call back function.
// CAN BE CHANGED: The parameter to osTimerDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal)
#define osTimerDef(name, function)          \
  extern osTimerDef_t os_timer_def_##name
#else
#define osTimerDef(name, function)          \
  OS_TIMER_EX os_timer_id_##name;           \
  osTimerDef_t os_timer_def_##name =        \
      {&os_timer_id_##name, (function) }
#endif

#define osTimer(name) \
  &os_timer_def_##name

osTimerId osTimerCreate( osTimerDef_t * timer_def, os_timer_type type,
  void * argument );
osStatus osTimerStart( osTimerId timer_id, uint32_t millisec );
osStatus osTimerStop( osTimerId timer_id );
osStatus osTimerDelete( osTimerId timer_id );

// ======= Signal Management ===================================================
//
int32_t osSignalSet( osThreadId thread_id, int32_t signals );
int32_t osSignalClear( osThreadId thread_id, int32_t signals );
osEvent osSignalWait( int32_t signals, uint32_t millisec );

// ======= Mutex Management ====================================================
#if defined (osObjectsExternal)
#define osMutexDef(name)  \
  extern osMutexDef_t os_mutex_def_##name
#else
#define osMutexDef(name)  \
  OS_RSEMA os_mutex_id_##name; \
  osMutexDef_t os_mutex_def_##name = { &os_mutex_id_##name }
#endif

#define osMutex(name)  \
  &os_mutex_def_##name

osMutexId osMutexCreate( osMutexDef_t * mutex_def );
osStatus osMutexWait( osMutexId mutex_id, uint32_t millisec );
osStatus osMutexRelease( osMutexId mutex_id );
osStatus osMutexDelete( osMutexId mutex_id );

// ======= Semaphore Management Functions ======================================

#if (defined (osFeature_Semaphore)  &&  (osFeature_Semaphore != 0))
//
// Define a Semaphore object.
// param         name          name of the semaphore object.
// CAN BE CHANGED: The parameter to osSemaphoreDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
//
#if defined (osObjectsExternal)
#define osSemaphoreDef(name)                              \
  extern osSemaphoreDef_t os_semaphore_def_##name
#else
#define osSemaphoreDef(name)                              \
  OS_CSEMA os_semaphore_id_##name;                        \
  osSemaphoreDef_t os_semaphore_def_##name = { &os_semaphore_id_##name }
#endif

#define osSemaphore(name)  \
  &os_semaphore_def_##name

osSemaphoreId osSemaphoreCreate( osSemaphoreDef_t * semaphore_def,
  int32_t count );
int32_t osSemaphoreWait( osSemaphoreId semaphore_id, uint32_t millisec );
osStatus osSemaphoreRelease( osSemaphoreId semaphore_id );
osStatus osSemaphoreDelete( osSemaphoreId semaphore_id );

#endif

// ============= Memory Pool Management Functions ==============================
//
#if (defined (osFeature_Pool)  &&  (osFeature_Pool != 0))
//
// \brief Define a Memory Pool.
// param         name          name of the memory pool.
// param         no            maximum number of blocks (objects) in the memory pool.
// param         type          data type of a single block (object).
// CAN BE CHANGED: The parameter to osPoolDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
#if defined (osObjectsExternal)
#define osPoolDef(name, no, type)   \
  extern osPoolDef_t os_pool_def_##name
#else
#define osPoolDef(name, no, type)   \
  OS_MEMF os_pool_id_##name; \
  uint32_t \
  os_pool_m_##name[ ( ( OS_MEMF_SIZEOF_BLOCKCONTROL + sizeof(type) + 3 ) / 4) * (no) ]; \
  osPoolDef_t \
  os_pool_def_##name = \
                       { &os_pool_id_##name, (no), \
                         ( ( ( OS_MEMF_SIZEOF_BLOCKCONTROL + sizeof(type) + 3 ) / 4) << 2 ), \
                         (os_pool_m_##name) }
#endif

#define osPool(name) \
  &os_pool_def_##name

osPoolId osPoolCreate( osPoolDef_t * pool_def );
void * osPoolAlloc( osPoolId pool_id );
void * osPoolCAlloc( osPoolId pool_id );
osStatus osPoolFree( osPoolId pool_id, void * block );

#endif

// ======= Message Queue Management Functions ==================================

#if (defined (osFeature_MessageQ)  &&  (osFeature_MessageQ != 0))
//
// \brief Create a Message Queue Definition.
// param         name          name of the queue.
// param         queue_sz      maximum number of messages in the queue.
// param         type          data type of a single message element (for debugger).
// CAN BE CHANGED: The parameter to osMessageQDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
//
#if defined (osObjectsExternal)
#define osMessageQDef(name, queue_sz, type)   \
  extern osMessageQDef_t os_messageQ_def_##name
#else
#define osMessageQDef(name, queue_sz, type)   \
  OS_MAILBOX os_messageQ_id_##name;\
  uint32_t os_messageQ_q_##name[ (queue_sz) ] = { 0 }; \
  osMessageQDef_t os_messageQ_def_##name = \
      { &os_messageQ_id_##name, (queue_sz << 2 ) , (os_messageQ_q_##name) }
#endif

#define osMessageQ(name) \
  &os_messageQ_def_##name

osMessageQId osMessageCreate( osMessageQDef_t * queue_def,
  osThreadId thread_id );
osStatus osMessagePut( osMessageQId queue_id, uint32_t info, uint32_t millisec );
osEvent osMessageGet( osMessageQId queue_id, uint32_t millisec );
osStatus osMessageDelete( osMessageQId queue_id );

#endif
// ======= Mail Queue Management Functions =====================================
#if (defined (osFeature_MailQ)  &&  (osFeature_MailQ != 0))
//
// \brief Create a Mail Queue Definition.
// param         name          name of the queue
// param         queue_sz      maximum number of messages in queue
// param         type          data type of a single message element
// CAN BE CHANGED: The parameter to osMailQDef shall be consistent but the
//       macro body is implementation specific in every CMSIS-RTOS.
//
#if defined (osObjectsExternal)
#define osMailQDef(name, queue_sz, type) \
  extern osMailQDef_t os_mailQ_def_##name
#else
#define osMailQDef(name, queue_sz, type) \
  osMailQ_cb os_MailQ_id_##name;\
  osPoolDef(mail_##name, queue_sz, type); \
  osMessageQDef(mail_##name, queue_sz); \
  osMailQDef_t os_mailQ_def_##name =  \
                                      { &os_MailQ_id_##name, osMessageQ(mail_##name), osPool(mail_##name), \
                                        queue_sz, ( ( (sizeof(type) + 3) >> 2 ) << 2 ) }
#endif

#define osMailQ(name)  \
  &os_mailQ_def_##name
osMailQId osMailCreate( osMailQDef_t * queue_def, osThreadId thread_id );
void * osMailAlloc( osMailQId queue_id, uint32_t millisec );
void * osMailCAlloc( osMailQId queue_id, uint32_t millisec );
osStatus osMailPut( osMailQId queue_id, void * mail );
osEvent osMailGet( osMailQId queue_id, uint32_t millisec );
osStatus osMailFree( osMailQId queue_id, void * mail );

#endif

// ============= Memory Management Functions ===================================

osStatus osMemoryLock( uint32_t timeout );

void osMemoryUnlock( void );

/*
 * ANSI C offers some basic dynamic memory management functions.
 * These are malloc, free, and realloc. Unfortunately, these routines are
 * not thread-safe, unless a special thread-safe implementation exists
 * in the compiler specific runtime libraries; they can only be used from
 * one task or by multiple tasks if they are called sequentially.
 *
 * Therefore, embOS offer task-safe variants of these routines.
 * These variants have the same names as their ANSI counterparts,
 * but are prefixed OS_; they are called OS_malloc(), OS_free(), OS_realloc().
 *
 * The thread-safe variants that embOS offers use the standard ANSI routines,
 * but they guarantee that the calls are serialized using a resource semaphore.
 *
 * If heap memory management is not supported by the standard C-libraries
 * for a specific CPU, embOS heap memory management is not implemented.
 *
 * Heap type memory management is part of the embOS libraries.
 * It does not use any resources if it is not referenced by the application
 * (that is, if the application does not use any memory management API function).
 *
 * Note that another aspect of these routines may still be a problem:
 * the memory used for the functions (known as heap) may fragment.
 *
 * This can lead to a situation where the total amount of memory is sufficient,
 * but there is not enough memory available in a single block
 * to satisfy an allocation request.
 *
 */

/* Allocates a block of size bytes of memory, returning a pointer
 * to the beginning of the block. The content of the newly allocated block of
 * memory is not initialized, remaining with indeterminate values.
 *
 * On success, a pointer to the memory block allocated by the function.
 * The type of this pointer is always void*, which can be cast to the desired
 * type of data pointer in order to be dereferenceable.
 *
 * If the function failed to allocate the requested block of memory,
 * a null pointer is returned.
 *
 */
void * osMalloc( size_t size, uint32_t timeout );

/* Allocates a block of memory for an array of num elements,
 * each of them size bytes long, and initializes all its bits to zero.
 *
 * The effective result is the allocation of a zero-initialized memory block
 * of (num*size) bytes.
 *
 * On success, a pointer to the memory block allocated by the function.
 * The type of this pointer is always void*, which can be cast to the desired
 * type of data pointer in order to be dereferenceable.
 *
 * If the function failed to allocate the requested block of memory,
 * a null pointer is returned.
 *
 */
void * osCalloc( size_t nelem, size_t elsize, uint32_t timeout );

/* Changes the size of the memory block pointed to by ptr.
 * The function may move the memory block to a new location (whose address is
 * returned by the function).
 *
 * The content of the memory block is preserved up to the lesser of the new
 * and old sizes, even if the block is moved to a new location.
 *
 * If the new size is larger, the value of the newly allocated portion
 * is indeterminate.
 *
 * In case that ptr is a null pointer, the function behaves like malloc,
 * assigning a new block of size bytes and returning a pointer to its beginning.
 *
 * If the function fails to allocate the requested block of memory,
 * a null pointer is returned, and the memory block pointed to by argument ptr
 * is not deallocated (it is still valid, and with its contents unchanged).
 *
 * A pointer to the reallocated memory block, which may be either the same
 * as ptr or a new location. The type of this pointer is void*, which can be
 * cast to the desired type of data pointer in order to be dereferenceable.
 */
void * osRealloc( void * ptr, size_t size, uint32_t timeout );

/* A block of memory previously allocated by a call to malloc, calloc or realloc
 * is deallocated, making it available again for further allocations.
 *
 * If ptr does not point to a block of memory allocated with the above functions
 * it causes undefined behavior.
 * If ptr is a null pointer, the function does nothing.
 *
 * Notice that this function does not change the value of ptr itself,
 * hence it still points to the same (now invalid) location.
 *
 */
void osFree( void * ptr );

/*
 * Informs RTOS that interrupt code is executing.
 *
 * If osEnterInterrupt() is used, it should be the first function to be called
 * in the interrupt handler. It must be used with osLeaveInterrupt() as the last
 * function called. The use of this function has the following effects, it:
 *
 * disables task switches
 * keeps interrupts in internal routines disabled.
 */
void osEnterInterrupt( void );

/*
 * Informs RTOS that the end of the interrupt routine has been reached;
 * executes task switching within ISR.
 *
 * If osLeaveInterrupt()is used, it should be the last function to be called
 * in the interrupt handler. If the interrupt has caused a task switch, it will
 * be executed (unless the program which was interrupted was in a critical region).
 *
 */
void osLeaveInterrupt( void );

uint32_t osDisableInterrupt( void );

void osRestoreInterrupt( uint32_t val );

#ifdef  __cplusplus
}
#endif

#endif  // __CMSIS_OS_H__
#include "cmsis_os.h"
#include <stdlib.h>

#define CMSIS2EMBOS(x)    ((x)+3)
#define EMBOS2CMSIS(x)    ( (osPriority)( (x) -3) )

CMSIS_OS_GLOBAL os_global;

//
// System Timer available
//
// Get the RTOS kernel system timer counter.
// MUST REMAIN UNCHANGED: osKernelSysTick shall be consistent in every CMSIS-RTOS.
// return : RTOS kernel system timer as 32-bit value
uint32_t osKernelSysTick0( void )
{
  // returns the system time in timer clock cycles
  return OS_GetTime_Cycles( );
}

// ============= Kernel Control Functions ======================================
//
// Initialize the RTOS Kernel for creating objects.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osKernelInitialize shall be consistent in every CMSIS-RTOS.
//
osStatus osKernelInitialize( void )
{
  OS_IncDI();
  OS_InitKern( );
  OS_InitHW( );
  return osOK;
}

// Start the RTOS Kernel.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osKernelStart shall be consistent in every CMSIS-RTOS.
//
osStatus osKernelStart( void )
{
  /* This function starts the embOS scheduler and schould be the last function
   * called from main().
   *
   * It will activate and start the task with the highest priority.
   * automatically enables interrupts, and never return
   */
  OS_Running = 1u;
  OS_StartASM( );
  return osOK;
}

osStatus osKernelStartThread( osThreadDef_t * thread_def, void * argument )
{
  osThreadCreate( thread_def, argument );
  return osKernelStart( );
}

// Check if the RTOS kernel is already started.
// MUST REMAIN UNCHANGED: osKernelRunning shall be consistent in every CMSIS-RTOS.
// return : 0 RTOS is not started, 1 RTOS is started.
//
int32_t osKernelRunning( void )
{
  return OS_IsRunning(); // OS_Running;
}

// ============= Thread Management =============================================
//
// Create a thread and add it to Active Threads and set it to state READY.
// param[in]   thread_def  thread definition referenced with osThread.
// param[in]   argument    pointer that is passed to the thread function as start argument.
// return : thread ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osThreadCreate shall be consistent in every CMSIS-RTOS.
//
osThreadId osThreadCreate( osThreadDef_t * thread_def, void * argument )
{
  OS_CreateTaskEx( thread_def->threadId, (char *) thread_def->name,
    CMSIS2EMBOS( thread_def->tpriority ),
    (void (*)( void * )) ( thread_def->pthread ), thread_def->stack,
    thread_def->stacksize, 2, argument );
  return thread_def->threadId;
}

// Return the thread ID of the current running thread.
// return : thread ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osThreadGetId shall be consistent in every CMSIS-RTOS.
//
osThreadId osThreadGetId( void )
{
  return OS_GetTaskID();
}

// Terminate execution of a thread and remove it from Active Threads.
// param[in]   thread_id   thread ID obtained by osThreadCreate or osThreadGetId.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osThreadTerminate shall be consistent in every CMSIS-RTOS.
//
osStatus osThreadTerminate( osThreadId thread_id )
{
  // If pTaskis the NULLpointer, the current task terminates.
  // The specified task will terminate immediately.
  // The memory used for stack and task control block can be reassigned.
  OS_TerminateTask( thread_id );
  return osOK;
}

// Pass control to next thread that is in state READY.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osThreadYield shall be consistent in every CMSIS-RTOS.
//
osStatus osThreadYield( void )
{
  // Calls the scheduler to force a task switch.
  OS_Yield( );
  return osOK;
}

// Change priority of an active thread.
// param[in]   thread_id   thread ID obtained by osThreadCreate or osThreadGetId.
// param[in]   priority    new priority value for the thread function.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osThreadSetPriority shall be consistent in every CMSIS-RTOS.
//
osStatus osThreadSetPriority( osThreadId thread_id, osPriority priority )
{
  OS_SetPriority( thread_id, CMSIS2EMBOS( priority ) );
  return osOK;
}

// Get current priority of an active thread.
// param[in]   thread_id   thread ID obtained by osThreadCreate or osThreadGetId.
// return : current priority value of the thread function.
// MUST REMAIN UNCHANGED: osThreadGetPriority shall be consistent in every CMSIS-RTOS.
//
osPriority osThreadGetPriority( osThreadId thread_id )
{
  return EMBOS2CMSIS( OS_GetPriority( thread_id ) );
}

// ============= Generic Wait Functions ========================================
//
// Wait for Timeout (Time Delay).
// param[in]   millisec    time delay value
// return : status code that indicates the execution status of the function.
//
osStatus osDelay( uint32_t millisec )
{
  OS_Delay( osKernelTicksByMilliSec( millisec ) );
  return osOK;
}

// Generic Wait available
//
// Wait for Signal, Message, Mail, or Timeout.
// param[in] millisec      timeout value or 0 in case of no time-out
// return : event that contains signal, message, or mail information or error code.
// MUST REMAIN UNCHANGED: osWait shall be consistent in every CMSIS-RTOS.
//
osEvent osWait( uint32_t millisec )
{
  osEvent event;
  event.status = osOK;
  return event;
}

// ============= Timer Management Functions ====================================
//
// Create a timer.
// param[in]   timer_def   timer object referenced with osTimer.
// param[in]   type      osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
// param[in]   argument    argument to the timer call back function.
// return : timer ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osTimerCreate shall be consistent in every CMSIS-RTOS.
//
osTimerId osTimerCreate( osTimerDef_t * timer_def, os_timer_type type,
  void * argument )
{
  OS_CreateTimerEx( timer_def->timerId,
    (OS_TIMER_EX_ROUTINE *) ( timer_def->ptimer ), -1, argument );
  return timer_def->timerId;
}

// Start or restart a timer.
// param[in]   timer_id    timer ID obtained by osTimerCreate.
// param[in]   millisec    time delay value of the timer.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osTimerStart shall be consistent in every CMSIS-RTOS.
//
osStatus osTimerStart( osTimerId timer_id, uint32_t millisec )
{
  OS_SetTimerPeriodEx( timer_id, osKernelTicksByMilliSec( millisec ) );
  OS_RetriggerTimerEx( timer_id );
  return osOK;
}

// Stop the timer.
// param[in]   timer_id    timer ID obtained by osTimerCreate.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osTimerStop shall be consistent in every CMSIS-RTOS.
//
osStatus osTimerStop( osTimerId timer_id )
{
  OS_StopTimerEx( timer_id );
  return osOK;
}

// Delete a timer that was created by osTimerCreate.
// param[in]   timer_id    timer ID obtained by osTimerCreate.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osTimerDelete shall be consistent in every CMSIS-RTOS.
//
osStatus osTimerDelete( osTimerId timer_id )
{
  OS_DeleteTimerEx( timer_id );
  return osOK;
}

// ============= Signal Management =============================================
//
// Set the specified Signal Flags of an active thread.
// param[in]   thread_id   thread ID obtained by osThreadCreate or osThreadGetId.
// param[in]   signals     specifies the signal flags of the thread that should be set.
// return : previous signal flags of the specified thread
//          or 0x80000000 in case of incorrect parameters.
// MUST REMAIN UNCHANGED: osSignalSet shall be consistent in every CMSIS-RTOS.
//
int32_t osSignalSet( osThreadId thread_id, int32_t signals )
{
  // Returns a list of events that have occurred for a specified task.
  // The event mask of the events that have actually occurred
  // the actual events remain signaled
  //
  int32_t result = OS_GetEventsOccurred( thread_id );
  OS_SignalEvent( signals, thread_id );
  return result;
}

int32_t OS_ClearEvent( osThreadId thread_id, int32_t signals )
{
  if ( thread_id == 0 )
    thread_id = osThreadGetId( );
  int32_t result = thread_id.Events;
  // uint32_t val = osDisableInterrupt( );
  OS_DisableInt( );   // MOV.W   R1, #0x80   MSR.W   BASEPRI, R1
  thread_id.Events &= ~signals;
  if ( OS_Global.Counters.Cnt.DI == 0 )
    OS_EnableInt( );  // MOV.W   R1, #0x00   MSR.W   BASEPRI, R1
  // osRestoreInterrupt( val );
  return result;
}

// Clear the specified Signal Flags of an active thread.
// param[in]   thread_id   thread ID obtained by osThreadCreate or osThreadGetId.
// param[in]   signals     specifies the signal flags of the thread that shall be cleared.
// return : previous signal flags of the specified thread
//          or 0x80000000 in case of incorrect parameters.
// MUST REMAIN UNCHANGED: osSignalClear shall be consistent in every CMSIS-RTOS.
//
int32_t osSignalClear( osThreadId thread_id, int32_t signals )
{
  // Returns the actual state of events
  // and then clears the events of a specified task.
  // Returns the actual state of events and then
  // clears ** the ALL events ** of a specified task.
  //
  // return OS_ClearEvents( thread_id );
  //
  return OS_ClearEvent( thread_id );
}

// Wait for one or more Signal Flags to become signaled for the current RUNNING thread.
// param[in]   signals     wait until all specified signal flags set or 0 for any single signal flag.
// param[in]   millisec    timeout value or 0 in case of no time-out.
// return : event flag information or error code.
// MUST REMAIN UNCHANGED: osSignalWait shall be consistent in every CMSIS-RTOS.
//
osEvent osSignalWait( int32_t signals, uint32_t millisec )
{
  osEvent event;
  event.status = osEventSignal;

  // Not allowed in ISR ?
  // event.status = osErrorISR
  //
  // The task is not suspended even if no events are signaled.
  if ( millisec == 0 )
  {
    // Returns a list of events that have occurred for a specified task.
    // The event mask of the events that have actually occurred.
    event.value.signals = OS_GetEventsOccurred( 0 );
  }

  else if ( millisec == osWaitForever )
  {
    if ( signals == 0 ) // Wait forever until any single signal flag
    {
      // Waits for one of the events specified in the bitmask and
      // clears the event memory after an event occurs
      event.value.signals = OS_WaitEvent( 0xFFFFFFFF );
    }

    else // Wait forever until all specified signal flags set
    {
      // Waits for one or more of the events specified by the Eventmask
      // and clears only those events that were specified in the eventmask.
      event.value.signals = OS_WaitSingleEvent( signals );
    }
  }

  else
  {
    if ( signals == 0 ) // Wait millisec until any single signal flag
    {
      // Waits for the specified events for a given time, and clears
      // ** the event memory ** after one of the requsted events occurs,
      // or after the timeout expired.
      event.value.signals = OS_WaitEventTimed( 0xFFFFFFFF,
        osKernelTicksByMilliSec( millisec ) );
    }

    else // Wait millisec until all specified signal flags set
    {
      // Waits for the specified events for a given time; after an event occurs,
      // only ** the requested events ** are cleared.
      event.value.signals = OS_WaitSingleEventTimed( signals,
        osKernelTicksByMilliSec( millisec ) );
    }
  }

  if ( event.value.signals == 0 )
  {
    event.status = ( millisec > 0 ) ? osEventTimeout : osOK;
  }

  return event;
}

// ============= Mutex Management ==============================================
//
/* Resource semaphores are used for managingresources by avoiding conflicts
 * caused by simultaneous use of a resource. The resource managed can be of
 * any kind: a part of the program that is not reentrant, a piece of hardware
 * like the display, a flash prom that can only be written to by a single task
 * at a time, a motor in a CNC control that can only be controlled by one task
 * at a time, and a lot more.
 *
 * The basic procedure is as follows:
 * Any task that uses a resource first claims it calling the OS_Use() or
 * OS_Request() routines of embOS. If the resource is available, the program
 * execution of the task continues, but the resource is blocked for other tasks.
 *
 * If a second task now tries to use the same resource while it is in use
 * by the first task, this second task is suspended until the first task releases
 * the resource. However, if the first task that uses the resource calls
 * OS_Use() again for that resource, it is not suspended because the resource
 * is blocked only for other tasks.
 *
 * A resource semaphore contains a counter that keeps track of how many times
 * the resource has been claimed by calling OS_Request() or OS_Use()
 * by a particular task. It is released when that counter reaches 0,
 * which means the OS_Unuse() routine has to be called exactly the same number
 * of times as OS_Use() or OS_Request(). If it is not, the resource remains
 * blocked for other tasks.
 *
 * On the other hand, a task cannot release a resource that it does not own
 * by calling OS_Unuse().
 *
 * counter = 0 after OS_CreateRSema()
 * counter++ : OS_Use() or OS_Request()
 * counter-- : OS_Unuse()
 *
 * A programmer can prefer mutex rather than creating a semaphore with count 1.
 */
// Create and Initialize a Mutex object.
// param[in]   mutex_def   mutex definition referenced with osMutex.
// return : mutex ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osMutexCreate shall be consistent in every CMSIS-RTOS.
//
osMutexId osMutexCreate( osMutexDef_t * mutex_def )
{
  OS_CreateRSema( mutex_def->mutexId );
  return mutex_def->mutexId;
}

// Wait until a Mutex becomes available.
// param[in]   mutex_id    mutex ID obtained by osMutexCreate.
// param[in]   millisec    timeout value or 0 in case of no time-out.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMutexWait shall be consistent in every CMSIS-RTOS.
//
osStatus osMutexWait( osMutexId mutex_id, uint32_t millisec )
{
  osStatus status = osOK;

  if ( millisec == 0 )
  {
    if ( OS_Request( mutex_id ) == 0 )
    {
      status = osErrorResource;
    }
  }

  else if ( millisec == osWaitForever )
  {
    OS_Use( mutex_id );
  }

  else if ( 0 == OS_UseTimed( mutex_id, osKernelTicksByMilliSec( millisec ) ) )
  {
    status = osErrorTimeoutResource;
  }

  return status;
}

// Release a Mutex that was obtained by osMutexWait.
// param[in]   mutex_id    mutex ID obtained by osMutexCreate.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMutexRelease shall be consistent in every CMSIS-RTOS.
//
osStatus osMutexRelease( osMutexId mutex_id )
{
  OS_Unuse( mutex_id );
  return osOK;
}

// Delete a Mutex that was created by osMutexCreate.
// param[in]   mutex_id    mutex ID obtained by osMutexCreate.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMutexDelete shall be consistent in every CMSIS-RTOS.
//
osStatus osMutexDelete( osMutexId mutex_id )
{
  OS_DeleteRSema( mutex_id );
  return osOK;
}

// ============= Semaphore Management Functions ================================
/* Counting semaphores are counters that are managed by embOS.
 * They are not as widely used as resource semaphores, events or mailboxes,
 * but they can be very useful sometimes.
 *
 * They are used in situations where a task needs to wait for something
 * that can be signaled one or more times.
 *
 * The semaphores can be accessed from any point, any task,
 * or any interrupt in any way.
 *
 * OS_CreateCSema()
 * Creates a counting semaphore with a specified initial count value
 *
 * OS_SignalCSema()
 * Increments the counter of a semaphore.
 * If one or more tasks are waiting for an event to be signaled to this
 * semaphore, the task that has the highest priority will become the running task
 *
 * OS_WaitCSema()
 * Decrements the counter of a semaphore.
 * If the counter of the semaphore is not 0, the counter is decremented
 * and program execution continues.
 * If the counter is 0, WaitCSema()waits until the counter is incremented by
 * another task, a timer or an interrupt handler via a call to OS_SignalCSema().
 * The counter is then decremented and program execution continues.
 *
 * OS_WaitCSemaTimed()
 * Decrements a semaphore counter if the semaphore is available
 * within a specified time.
 * If the semaphore was not signaled within the specified time, the program
 * execution continues but returns a value of 0.
 *
 * OS_CSemaRequest()
 * Decrements the counter of a semaphore, if it is signaled.
 * If the counter is 0, OS_CSemaRequest() does not wait and does not modify
 * the semaphore counter. The function returns with error state.
 *
 */

// Create and Initialize a Semaphore object used for managing resources.
// param[in]   semaphore_def semaphore definition referenced with osSemaphore.
// param[in]   count     number of available resources.
// return : semaphore ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
//
osSemaphoreId osSemaphoreCreate( osSemaphoreDef_t * semaphore_def,
  int32_t count )
{
  // Creates a counting semaphore with a specified initial count value.
  OS_CreateCSema( semaphore_def->semaphoreId, count );
  return semaphore_def->semaphoreId;
}

// Wait until a Semaphore token becomes available.
// param[in]  semaphore_id  semaphore object referenced with osSemaphoreCreate.
// param[in]  millisec      timeout value or 0 in case of no time-out.
// return :   number of available tokens : (tokens after wait) + 1
//            or -1 in case of incorrect parameters.
// MUST REMAIN UNCHANGED: osSemaphoreWait shall be consistent in every CMSIS-RTOS.
//
int32_t osSemaphoreWait( osSemaphoreId semaphore_id, uint32_t millisec )
{
  int32_t result = -1; // OS_WaitCSemaTimed() timeout

  if ( millisec == 0 )
  {
    // Decrements the counter of a semaphore, if it is signaled
    if ( OS_CSemaRequest( semaphore_id ) )
    {
      // Returns the counter value of a specified semaphore
      result = OS_GetCSemaValue( semaphore_id );
    }
  }

  else if ( millisec == osWaitForever )
  {
    // Decrements the counter of a semaphore
    // If the counter of the semaphore is not 0, the counter is decremented
    // and program execution continues.
    // If the counter is 0, WaitCSema() waits until the counter is incremented
    // by another task, a timer or an interrupt handler
    // via a call to OS_SignalCSema().
    OS_WaitCSema( semaphore_id );

    // Returns the counter value of a specified semaphore
    result = OS_GetCSemaValue( semaphore_id );
  }
  // Decrements a semaphore counter if the semaphore is available
  // within a specified time.
  else if ( OS_WaitCSemaTimed( semaphore_id,
    osKernelTicksByMilliSec( millisec ) ) )
  {
    result = OS_GetCSemaValue( semaphore_id );
  }

  return result + 1;
}

/**
 * @brief Release a Semaphore token
 * @param  semaphore_id  semaphore object referenced with osSemaphore.
 * @retval  status code that indicates the execution status of the function.
 * @note   MUST REMAIN UNCHANGED: osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
 */
osStatus osSemaphoreRelease( osSemaphoreId semaphore_id )
{
  // Increments the counter of a semaphore
  // If one or more tasks are waiting for an event to be signaled to
  // this semaphore, the task that has the highest priority will
  // become the running task.
  OS_SignalCSema( semaphore_id );
  return osOK;
}

// Release a Semaphore token.
// param[in]     semaphore_id  semaphore object referenced with osSemaphoreCreate.
// return :  status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
//
osStatus osSemaphoreDelete( osSemaphoreId semaphore_id )
{
  // Deletes a specified semaphore.
  // Before deleting a semaphore, make sure that no task is waiting for it
  // and that notask will signal that semaphore at a later point.
  OS_DeleteCSema( semaphore_id );
  return osOK;
}

// ============= Memory Pool Management Functions ==============================

// Create and Initialize a memory pool.
// param[in]   pool_def    memory pool definition referenced with osPool.
// return : memory pool ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osPoolCreate shall be consistent in every CMSIS-RTOS.
//
osPoolId osPoolCreate( osPoolDef_t * pool_def )
{
  // void OS_MEMF_Create (OS_MEMF* pMEMF, void* pPool, OS_UINT NumBlocks, OS_UINT BlockSize);
  // BlockSize is aligment at 4 Bytes !!!
  //
  OS_MEMF_Create( pool_def->poolId, pool_def->pool, pool_def->pool_sz,
    pool_def->item_sz );
  return pool_def->poolId;
}

// Allocate a memory block from a memory pool.
// param[in]   pool_id     memory pool ID obtain referenced with osPoolCreate.
// return : address of the allocated memory block or NULL in case of no memory available.
// MUST REMAIN UNCHANGED: osPoolAlloc shall be consistent in every CMSIS-RTOS.
//
// Requests allocation of a memory block.
// Waits until a block of memory is available
// If there is no free memory block in the pool, the calling task is suspended
// until a memory block becomes available.
//
void * osPoolAlloc( osPoolId pool_id )
{
  return OS_MEMF_Alloc( pool_id, 0 );
}

// Requests allocation of a memory block. Waits until a block of memory
// is available or the timeout has expired.
//
void * osPoolAllocTimed( osPoolId pool_id, uint32_t millisec )
{
  return OS_MEMF_AllocTimed( pool_id, osKernelTicksByMilliSec( millisec ), 0 );
}

// Requests allocation of a memory block. Continues execution in any case.
// The calling task is never suspended by calling OS_MEMF_Request()
//
void * osPoolRequest( osPoolId pool_id )
{
  return OS_MEMF_Request( pool_id, 0 );
}

// Allocate a memory block from a memory pool and set memory block to zero.
// param[in]   pool_id     memory pool ID obtain referenced with osPoolCreate.
// return : address of the allocated memory block or NULL in case of no memory available.
// MUST REMAIN UNCHANGED: osPoolCAlloc shall be consistent in every CMSIS-RTOS.
void * osPoolCAlloc( osPoolId pool_id )
{
  void * p = osPoolAlloc( pool_id );

  if ( p )
  {
    memset( p, 0, pool_id->BlockSize );
  }

  return p;
}

// Return an allocated memory block back to a specific memory pool.
// param[in]   pool_id     memory pool ID obtain referenced with osPoolCreate.
// param[in]   block     address of the allocated memory block that is returned to the memory pool.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osPoolFree shall be consistent in every CMSIS-RTOS.
osStatus osPoolFree( osPoolId pool_id, void * block )
{
  OS_MEMF_Release( pool_id, block );
  return osOK;
}

// ============= Message Queue Management Functions =============================

// Create and Initialize a Message Queue.
// param[in]   queue_def   queue definition referenced with osMessageQ.
// param[in]   thread_id   thread ID (obtained by osThreadCreate or osThreadGetId) or NULL.
// return : message queue ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osMessageCreate shall be consistent in every CMSIS-RTOS.
//
osMessageQId osMessageCreate( osMessageQDef_t * queue_def,
  osThreadId thread_id )
{
  OS_CreateMB( queue_def->messageQId, 4, queue_def->queue_sz, queue_def->pool );
  return queue_def->messageQId;
}

// Put a Message to a Queue.
// param[in]   queue_id    message queue ID obtained with osMessageCreate.
// param[in]   info      message information.
// param[in]   millisec    timeout value or 0 in case of no time-out.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMessagePut shall be consistent in every CMSIS-RTOS.
//
osStatus osMessagePut( osMessageQId queue_id, uint32_t info, uint32_t millisec )
{
  osStatus status = osOK;

  if ( millisec == 0 )
  {
    if ( OS_PutMailCond( queue_id, (const void *) &info ) > 0 )
    {
      status = osErrorResource;
    }
  }
  else if ( millisec == osWaitForever )
  {
    OS_PutMail( queue_id, (const void *) &info );
  }
  else
  {
    OS_TIME osKernelTickCountPrev = osKernelTickCount();

    while ( 1 )
    {
      if ( OS_PutMailCond( queue_id, (const void *) &info ) == 0 )
        return status;

      osDelay( 1 );

      if ( ( osKernelTickCount() - osKernelTickCountPrev )
        > osKernelTicksByMilliSec( millisec ) )
        return osErrorTimeoutResource;
    }
  }

  return status;
}

// Get a Message or Wait for a Message from a Queue.
// param[in]   queue_id    message queue ID obtained with osMessageCreate.
// param[in]   millisec    timeout value or 0 in case of no time-out.
// return : event information that includes status code.
// MUST REMAIN UNCHANGED: osMessageGet shall be consistent in every CMSIS-RTOS.
//
osEvent osMessageGet( osMessageQId queue_id, uint32_t millisec )
{
  osEvent event;
  event.status = osEventMessage;

  // The task is not suspended even if no events are signaled.
  if ( millisec == 0 )
  {
    if ( OS_GetMailCond( queue_id, &event.value.v ) > 0 )
    {
      event.status = osOK;
    }
  }

  else if ( millisec == osWaitForever )
  {
    OS_GetMail( queue_id, &event.value.v );
  }

  else if ( OS_GetMailTimed( queue_id, &event.value.v,
    osKernelTicksByMilliSec( millisec ) ) > 0 )
  {
    event.status = osEventTimeout;
  }

  return event;
}

osStatus osMessageDelete( osMessageQId queue_id )
{
  OS_DeleteMB( queue_id );
  return osOK;
}

// ============= Mail Queue Management Functions ===============================

// Mail Queues available
// Create and Initialize mail queue.
// param[in]   queue_def   reference to the mail queue definition obtain with osMailQ
// param[in]   thread_id   thread ID (obtained by osThreadCreate or osThreadGetId) or NULL.
// return : mail queue ID for reference by other functions or NULL in case of error.
// MUST REMAIN UNCHANGED: osMailCreate shall be consistent in every CMSIS-RTOS.
//
osMailQId osMailCreate( osMailQDef_t * queue_def, osThreadId thread_id )
{
  queue_def->mailId->messageId = osMessageCreate( queue_def->messageQDef,
    thread_id );
  queue_def->mailId->poolId = osPoolCreate( queue_def->poolDef );
  return queue_def->mailId;
}

// Allocate a memory block from a mail.
// param[in]   queue_id    mail queue ID obtained with osMailCreate.
// param[in]   millisec    timeout value or 0 in case of no time-out
// return : pointer to memory block that can be filled with mail or NULL in case of error.
// MUST REMAIN UNCHANGED: osMailAlloc shall be consistent in every CMSIS-RTOS.
//
void * osMailAlloc( osMailQId queue_id, uint32_t millisec )
{
  void * p;

  if ( millisec == 0 )
  {
    p = osPoolRequest( queue_id->poolId );
  }

  else if ( millisec == osWaitForever )
  {
    p = osPoolAlloc( queue_id->poolId );
  }

  else
  {
    p = osPoolAllocTimed( queue_id->poolId, millisec );
  }

  return p;
}

// Allocate a memory block from a mail and set memory block to zero.
// param[in]   queue_id    mail queue ID obtained with osMailCreate.
// param[in]   millisec    timeout value or 0 in case of no time-out
// return : pointer to memory block that can be filled with mail or NULL in case of error.
// MUST REMAIN UNCHANGED: osMailCAlloc shall be consistent in every CMSIS-RTOS.
//
void * osMailCAlloc( osMailQId queue_id, uint32_t millisec )
{
  void * p = osMailAlloc( queue_id, millisec );

  if ( p )
  {
    memset( p, 0, queue_id->poolId->BlockSize );
  }

  return p;
}

// Put a mail to a queue.
// param[in]   queue_id    mail queue ID obtained with osMailCreate.
// param[in]   mail      memory block previously allocated with osMailAlloc or osMailCAlloc.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMailPut shall be consistent in every CMSIS-RTOS.
//
osStatus osMailPut( osMailQId queue_id, void * mail )
{
  return osMessagePut( queue_id->messageId, (uint32_t) mail, osWaitForever );
}

// Get a mail from a queue.
// param[in]   queue_id    mail queue ID obtained with osMailCreate.
// param[in]   millisec    timeout value or 0 in case of no time-out
// return : event that contains mail information or error code.
// MUST REMAIN UNCHANGED: osMailGet shall be consistent in every CMSIS-RTOS.
//
osEvent osMailGet( osMailQId queue_id, uint32_t millisec )
{
  osEvent event = osMessageGet( queue_id->messageId, millisec );

  if ( event.status == osEventMessage )
  {
    event.status = osEventMail;
  }

  return event;
}

// Free a memory block from a mail.
// param[in]   queue_id    mail queue ID obtained with osMailCreate.
// param[in]   mail      pointer to the memory block that was obtained with osMailGet.
// return : status code that indicates the execution status of the function.
// MUST REMAIN UNCHANGED: osMailFree shall be consistent in every CMSIS-RTOS.
//
osStatus osMailFree( osMailQId queue_id, void * mail )
{
  return osPoolFree( queue_id->poolId, mail );
}

// ============= Memory Management Functions ===================================

static osMutexDef( cmsis_memory )
;
static osMutexId cmsis_memory;

osStatus osMemoryLock( uint32_t timeout )
{
  if ( cmsis_memory == 0 )
    cmsis_memory = osMutexCreate( osMutex( cmsis_memory ) );

  return osMutexWait( cmsis_memory, timeout );
}

void osMemoryUnlock( void )
{
  osMutexRelease( cmsis_memory );
}

/* Allocates a block of size bytes of memory, returning a pointer
 * to the beginning of the block. The content of the newly allocated block of
 * memory is not initialized, remaining with indeterminate values.
 *
 * On success, a pointer to the memory block allocated by the function.
 * The type of this pointer is always void*, which can be cast to the desired
 * type of data pointer in order to be dereferenceable.
 *
 * If the function failed to allocate the requested block of memory,
 * a null pointer is returned.
 *
 */
void * osMalloc( size_t size, uint32_t timeout )
{
  void * p = 0;
  osStatus status = osMemoryLock( timeout );
  if ( status == osOK )
  {
    p = malloc( size );
    osMemoryUnlock( );
  }
  return p;
}

/* Allocates a block of memory for an array of num elements,
 * each of them size bytes long, and initializes all its bits to zero.
 *
 * The effective result is the allocation of a zero-initialized memory block
 * of (num*size) bytes.
 *
 * On success, a pointer to the memory block allocated by the function.
 * The type of this pointer is always void*, which can be cast to the desired
 * type of data pointer in order to be dereferenceable.
 *
 * If the function failed to allocate the requested block of memory,
 * a null pointer is returned.
 *
 */
void * osCalloc( size_t nelem, size_t elsize, uint32_t timeout )
{
  void * p = osMalloc( nelem * elsize, timeout );

  if ( p )
  {
    memset( p, 0, nelem * elsize );
  }

  return p;
}

/* Changes the size of the memory block pointed to by ptr.
 * The function may move the memory block to a new location (whose address is
 * returned by the function).
 *
 * The content of the memory block is preserved up to the lesser of the new
 * and old sizes, even if the block is moved to a new location.
 *
 * If the new size is larger, the value of the newly allocated portion
 * is indeterminate.
 *
 * In case that ptr is a null pointer, the function behaves like malloc,
 * assigning a new block of size bytes and returning a pointer to its beginning.
 *
 * If the function fails to allocate the requested block of memory,
 * a null pointer is returned, and the memory block pointed to by argument ptr
 * is not deallocated (it is still valid, and with its contents unchanged).
 *
 * A pointer to the reallocated memory block, which may be either the same
 * as ptr or a new location. The type of this pointer is void*, which can be
 * cast to the desired type of data pointer in order to be dereferenceable.
 */
void * osRealloc( void * ptr, size_t size, uint32_t timeout )
{
  void * p = 0;
  osStatus status = osMemoryLock( timeout );
  if ( status == osOK )
  {
    p = realloc( ptr, size );
    osMemoryUnlock( );
  }
  return p;
}

/* A block of memory previously allocated by a call to malloc, calloc or realloc
 * is deallocated, making it available again for further allocations.
 *
 * If ptr does not point to a block of memory allocated with the above functions
 * it causes undefined behavior.
 * If ptr is a null pointer, the function does nothing.
 *
 * Notice that this function does not change the value of ptr itself,
 * hence it still points to the same (now invalid) location.
 *
 */
void osFree( void * ptr )
{
  osMemoryLock( osWaitForever );
  free( ptr );
  osMemoryUnlock( );
}

/*
 * Informs RTOS that interrupt code is executing.
 *
 * If osEnterInterrupt() is used, it should be the first function to be called
 * in the interrupt handler. It must be used with osLeaveInterrupt() as the last
 * function called. The use of this function has the following effects, it:
 *
 * disables task switches
 * keeps interrupts in internal routines disabled.
 */
void osEnterInterrupt( void )
{
  OS_EnterInterrupt()
  ;
}

/*
 * Informs RTOS that the end of the interrupt routine has been reached;
 * executes task switching within ISR.
 *
 * If osLeaveInterrupt()is used, it should be the last function to be called
 * in the interrupt handler. If the interrupt has caused a task switch, it will
 * be executed (unless the program which was interrupted was in a critical region).
 *
 */
void osLeaveInterrupt( void )
{
  OS_LeaveInterrupt()
  ;
}

uint32_t osDisableInterrupt( void )
{
  __istate_t s = __get_interrupt_state( );
  __disable_interrupt( );
  return (uint32_t) s;

}

void osRestoreInterrupt( uint32_t val )
{
  __set_interrupt_state( (__istate_t ) val );
}
#include "cmsis_os.h"

#if defined(osFeature_MainThread) && (osFeature_MainThread > 0 )

/*----------------------------------------------------------------------------
 *      RTX Startup
 *---------------------------------------------------------------------------*/

/* Main Thread definition */
extern int main (void);

osThreadDef( main, main, osPriorityNormal, 1, OS_MAINSTKSIZE );

extern int  __low_level_init(void);
extern void __iar_data_init3(void);
extern void exit(int arg);

__noreturn __stackless void __cmain(void) {
  int a;

  if (__low_level_init() != 0) {
    __iar_data_init3();
  }
  osKernelInitialize();
  osThreadCreate(&os_thread_def_main, NULL);
  a = osKernelStart();
  exit(a);
}

#endif

 

你可能感兴趣的:(cms)