1577 lines
50 KiB
C
1577 lines
50 KiB
C
/*
|
|
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
|
|
|
|
This file is part of ChibiOS.
|
|
|
|
ChibiOS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ChibiOS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* @file nil/include/ch.h
|
|
* @brief Nil RTOS main header file.
|
|
* @details This header includes all the required kernel headers so it is the
|
|
* only header you usually need to include in your application.
|
|
*
|
|
* @addtogroup NIL_KERNEL
|
|
* @{
|
|
*/
|
|
|
|
#ifndef CH_H
|
|
#define CH_H
|
|
|
|
#include "chtypes.h"
|
|
#include "chconf.h"
|
|
#include "chlicense.h"
|
|
|
|
/*===========================================================================*/
|
|
/* Module constants. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief ChibiOS/NIL identification macro.
|
|
*/
|
|
#define _CHIBIOS_NIL_
|
|
|
|
/**
|
|
* @brief Stable release flag.
|
|
*/
|
|
#define CH_KERNEL_STABLE 1
|
|
|
|
/**
|
|
* @name ChibiOS/NIL version identification
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Kernel version string.
|
|
*/
|
|
#define CH_KERNEL_VERSION "3.2.2"
|
|
|
|
/**
|
|
* @brief Kernel version major number.
|
|
*/
|
|
#define CH_KERNEL_MAJOR 3
|
|
|
|
/**
|
|
* @brief Kernel version minor number.
|
|
*/
|
|
#define CH_KERNEL_MINOR 2
|
|
|
|
/**
|
|
* @brief Kernel version patch number.
|
|
*/
|
|
#define CH_KERNEL_PATCH 2
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Constants for configuration options
|
|
*/
|
|
/**
|
|
* @brief Generic 'false' preprocessor boolean constant.
|
|
* @note It is meant to be used in configuration files as switch.
|
|
*/
|
|
#if !defined(FALSE) || defined(__DOXYGEN__)
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
/**
|
|
* @brief Generic 'true' preprocessor boolean constant.
|
|
* @note It is meant to be used in configuration files as switch.
|
|
*/
|
|
#if !defined(TRUE) || defined(__DOXYGEN__)
|
|
#define TRUE 1
|
|
#endif
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Wakeup messages
|
|
* @{
|
|
*/
|
|
#define MSG_OK (msg_t)0 /**< @brief OK wakeup message. */
|
|
#define MSG_TIMEOUT (msg_t)-1 /**< @brief Wake-up caused by
|
|
a timeout condition. */
|
|
#define MSG_RESET (msg_t)-2 /**< @brief Wake-up caused by
|
|
a reset condition. */
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Special time constants
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Zero time specification for some functions with a timeout
|
|
* specification.
|
|
* @note Not all functions accept @p TIME_IMMEDIATE as timeout parameter,
|
|
* see the specific function documentation.
|
|
*/
|
|
#define TIME_IMMEDIATE ((sysinterval_t)-1)
|
|
|
|
/**
|
|
* @brief Infinite time specification for all functions with a timeout
|
|
* specification.
|
|
*/
|
|
#define TIME_INFINITE ((sysinterval_t)0)
|
|
|
|
/**
|
|
* @brief Maximum interval constant usable as timeout.
|
|
*/
|
|
#define TIME_MAX_INTERVAL ((sysinterval_t)-2)
|
|
|
|
/**
|
|
* @brief Maximum system of system time before it wraps.
|
|
*/
|
|
#define TIME_MAX_SYSTIME ((systime_t)-1)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Thread state related macros
|
|
* @{
|
|
*/
|
|
#define NIL_STATE_READY (tstate_t)0 /**< @brief Thread ready or
|
|
executing. */
|
|
#define NIL_STATE_SLEEPING (tstate_t)1 /**< @brief Thread sleeping. */
|
|
#define NIL_STATE_SUSP (tstate_t)2 /**< @brief Thread suspended. */
|
|
#define NIL_STATE_WTQUEUE (tstate_t)3 /**< @brief On queue or semaph. */
|
|
#define NIL_STATE_WTOREVT (tstate_t)4 /**< @brief Waiting for events. */
|
|
#define NIL_THD_IS_READY(tp) ((tp)->state == NIL_STATE_READY)
|
|
#define NIL_THD_IS_SLEEPING(tp) ((tp)->state == NIL_STATE_SLEEPING)
|
|
#define NIL_THD_IS_SUSP(tp) ((tp)->state == NIL_STATE_SUSP)
|
|
#define NIL_THD_IS_WTQUEUE(tp) ((tp)->state == NIL_STATE_WTQUEUE)
|
|
#define NIL_THD_IS_WTOREVT(tp) ((tp)->state == NIL_STATE_WTOREVT)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Events related macros
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief All events allowed mask.
|
|
*/
|
|
#define ALL_EVENTS ((eventmask_t)-1)
|
|
|
|
/**
|
|
* @brief Returns an event mask from an event identifier.
|
|
*/
|
|
#define EVENT_MASK(eid) ((eventmask_t)(1 << (eid)))
|
|
/** @} */
|
|
|
|
/*===========================================================================*/
|
|
/* Module pre-compile time settings. */
|
|
/*===========================================================================*/
|
|
|
|
/*-*
|
|
* @brief Number of user threads in the application.
|
|
* @note This number is not inclusive of the idle thread which is
|
|
* implicitly handled.
|
|
*/
|
|
#if !defined(CH_CFG_NUM_THREADS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_NUM_THREADS 2
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief System time counter resolution.
|
|
* @note Allowed values are 16 or 32 bits.
|
|
*/
|
|
#if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__)
|
|
#define CH_CFG_ST_RESOLUTION 32
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief System tick frequency.
|
|
* @note This value together with the @p CH_CFG_ST_RESOLUTION
|
|
* option defines the maximum amount of time allowed for
|
|
* timeouts.
|
|
*/
|
|
#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__)
|
|
#define CH_CFG_ST_FREQUENCY 100
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Time delta constant for the tick-less mode.
|
|
* @note If this value is zero then the system uses the classic
|
|
* periodic tick. This value represents the minimum number
|
|
* of ticks that is safe to specify in a timeout directive.
|
|
* The value one is not valid, timeouts are rounded up to
|
|
* this value.
|
|
*/
|
|
#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__)
|
|
#define CH_CFG_ST_TIMEDELTA 0
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Semaphores APIs.
|
|
* @details If enabled then the Semaphores APIs are included in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_SEMAPHORES TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Mutexes APIs.
|
|
* @details If enabled then the mutexes APIs are included in the kernel.
|
|
*
|
|
* @note Feature not currently implemented.
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_MUTEXES FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Events Flags APIs.
|
|
* @details If enabled then the event flags APIs are included in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_EVENTS TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Mailboxes APIs.
|
|
* @details If enabled then the asynchronous messages (mailboxes) APIs are
|
|
* included in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
* @note Requires @p CH_CFG_USE_SEMAPHORES.
|
|
*/
|
|
#if !defined(CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_MAILBOXES TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Core Memory Manager APIs.
|
|
* @details If enabled then the core memory manager APIs are included
|
|
* in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_MEMCORE) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_MEMCORE TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Heap Allocator APIs.
|
|
* @details If enabled then the memory heap allocator APIs are included
|
|
* in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_HEAP TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Memory Pools Allocator APIs.
|
|
* @details If enabled then the memory pools allocator APIs are included
|
|
* in the kernel.
|
|
*
|
|
* @note The default is @p TRUE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_MEMPOOLS TRUE
|
|
#endif
|
|
/**
|
|
* @brief Objects Factory APIs.
|
|
* @details If enabled then the objects factory APIs are included in the
|
|
* kernel.
|
|
*
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_CFG_USE_FACTORY) || defined(__DOXYGEN__)
|
|
#define CH_CFG_USE_FACTORY TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Maximum length for object names.
|
|
* @details If the specified length is zero then the name is stored by
|
|
* pointer but this could have unintended side effects.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enables the registry of generic objects.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enables factory for generic buffers.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enables factory for semaphores.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_SEMAPHORES) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_SEMAPHORES TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enables factory for mailboxes.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_MAILBOXES) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_MAILBOXES TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Enables factory for objects FIFOs.
|
|
*/
|
|
#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_FACTORY_OBJ_FIFOS TRUE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Debug option, kernel statistics.
|
|
*
|
|
* @note Feature not currently implemented.
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_DBG_STATISTICS) || defined(__DOXYGEN__)
|
|
#define CH_DBG_STATISTICS FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Debug option, system state check.
|
|
* @note This is a planned feature, not yet implemented.
|
|
*
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
|
|
#define CH_DBG_SYSTEM_STATE_CHECK FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Debug option, parameters checks.
|
|
*
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
|
|
#define CH_DBG_ENABLE_CHECKS FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief System assertions.
|
|
*
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
|
|
#define CH_DBG_ENABLE_ASSERTS FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Stack check.
|
|
*
|
|
* @note The default is @p FALSE.
|
|
*/
|
|
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
|
|
#define CH_DBG_ENABLE_STACK_CHECK FALSE
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief System initialization hook.
|
|
*/
|
|
#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
|
|
#define CH_CFG_SYSTEM_INIT_HOOK() {}
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Threads descriptor structure extension.
|
|
* @details User fields added to the end of the @p thread_t structure.
|
|
*/
|
|
#if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
|
|
#define CH_CFG_THREAD_EXT_FIELDS
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Threads initialization hook.
|
|
*/
|
|
#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
|
|
#define CH_CFG_THREAD_EXT_INIT_HOOK(tp) {}
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Idle thread enter hook.
|
|
* @note This hook is invoked within a critical zone, no OS functions
|
|
* should be invoked from here.
|
|
* @note This macro can be used to activate a power saving mode.
|
|
*/
|
|
#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__)
|
|
#define CH_CFG_IDLE_ENTER_HOOK() {}
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief Idle thread leave hook.
|
|
* @note This hook is invoked within a critical zone, no OS functions
|
|
* should be invoked from here.
|
|
* @note This macro can be used to deactivate a power saving mode.
|
|
*/
|
|
#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__)
|
|
#define CH_CFG_IDLE_LEAVE_HOOK() {}
|
|
#endif
|
|
|
|
/*-*
|
|
* @brief System halt hook.
|
|
*/
|
|
#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
|
|
#define CH_CFG_SYSTEM_HALT_HOOK(reason) {}
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Derived constants and error checks. */
|
|
/*===========================================================================*/
|
|
|
|
/* License checks.*/
|
|
#if !defined(CH_CUSTOMER_LIC_NIL) || !defined(CH_LICENSE_FEATURES)
|
|
#error "malformed chlicense.h"
|
|
#endif
|
|
|
|
#if CH_CUSTOMER_LIC_NIL == FALSE
|
|
#error "ChibiOS/NIL not licensed"
|
|
#endif
|
|
|
|
#if (CH_LICENSE_FEATURES != CH_FEATURES_FULL) && \
|
|
(CH_LICENSE_FEATURES != CH_FEATURES_INTERMEDIATE) && \
|
|
(CH_LICENSE_FEATURES != CH_FEATURES_BASIC)
|
|
#error "invalid CH_LICENSE_FEATURES setting"
|
|
#endif
|
|
|
|
/* Restrictions in basic and intermediate modes.*/
|
|
#if (CH_LICENSE_FEATURES == CH_FEATURES_INTERMEDIATE) || \
|
|
(CH_LICENSE_FEATURES == CH_FEATURES_BASIC)
|
|
|
|
/* System tick limited to 1000hz.*/
|
|
#if CH_CFG_ST_FREQUENCY > 1000
|
|
#undef CH_CFG_ST_FREQUENCY
|
|
#define CH_CFG_ST_FREQUENCY 1000
|
|
#endif
|
|
|
|
#endif /* (CH_LICENSE_FEATURES == CH_FEATURES_INTERMEDIATE) ||
|
|
(CH_LICENSE_FEATURES == CH_FEATURES_BASIC) */
|
|
|
|
/* Restrictions in basic mode.*/
|
|
#if CH_LICENSE_FEATURES == CH_FEATURES_BASIC
|
|
|
|
/* Tick-Less mode restricted.*/
|
|
#undef CH_CFG_ST_TIMEDELTA
|
|
#define CH_CFG_ST_TIMEDELTA 0
|
|
|
|
#endif /* CH_LICENSE_FEATURES == CH_FEATURES_BASIC */
|
|
|
|
#if !defined(_CHIBIOS_NIL_CONF_)
|
|
#error "missing or wrong configuration file"
|
|
#endif
|
|
|
|
#if !defined(_CHIBIOS_NIL_CONF_VER_3_2_)
|
|
#error "obsolete or unknown configuration file"
|
|
#endif
|
|
|
|
#if CH_CFG_NUM_THREADS < 1
|
|
#error "at least one thread must be defined"
|
|
#endif
|
|
|
|
#if CH_CFG_NUM_THREADS > 16
|
|
#error "ChibiOS/NIL is not recommended for thread-intensive applications," \
|
|
"consider ChibiOS/RT instead"
|
|
#endif
|
|
|
|
#if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32)
|
|
#error "invalid CH_CFG_ST_RESOLUTION specified, must be 16 or 32"
|
|
#endif
|
|
|
|
#if CH_CFG_ST_FREQUENCY <= 0
|
|
#error "invalid CH_CFG_ST_FREQUENCY specified, must be greater than zero"
|
|
#endif
|
|
|
|
#if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1)
|
|
#error "invalid CH_CFG_ST_TIMEDELTA specified, must " \
|
|
"be zero or greater than one"
|
|
#endif
|
|
|
|
#if CH_CFG_USE_MUTEXES == TRUE
|
|
#error "mutexes not yet supported"
|
|
#endif
|
|
|
|
#if CH_DBG_STATISTICS == TRUE
|
|
#error "statistics not yet supported"
|
|
#endif
|
|
|
|
#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || \
|
|
(CH_DBG_ENABLE_CHECKS == TRUE) || \
|
|
(CH_DBG_ENABLE_ASSERTS == TRUE) || \
|
|
(CH_DBG_ENABLE_STACK_CHECK == TRUE)
|
|
#define NIL_DBG_ENABLED TRUE
|
|
#else
|
|
#define NIL_DBG_ENABLED FALSE
|
|
#endif
|
|
|
|
/** Boundaries of the idle thread boundaries, only required if stack checking
|
|
is enabled.*/
|
|
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
|
#define THD_IDLE_BASE (&__main_thread_stack_base__)
|
|
#define THD_IDLE_END (&__main_thread_stack_end__)
|
|
#else
|
|
#define THD_IDLE_BASE NULL
|
|
#define THD_IDLE_END NULL
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Module data structures and types. */
|
|
/*===========================================================================*/
|
|
|
|
#if (CH_CFG_ST_RESOLUTION == 32) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief Type of system time.
|
|
* @note It is selectable in configuration between 16 or 32 bits.
|
|
*/
|
|
typedef uint32_t systime_t;
|
|
|
|
/**
|
|
* @brief Type of time interval.
|
|
* @note It is selectable in configuration between 16 or 32 bits.
|
|
*/
|
|
typedef uint32_t sysinterval_t;
|
|
|
|
/**
|
|
* @brief Type of time conversion variable.
|
|
* @note This type must have double width than other time types, it is
|
|
* only used internally for conversions.
|
|
*/
|
|
typedef uint64_t time_conv_t;
|
|
|
|
#else
|
|
typedef uint16_t systime_t;
|
|
typedef uint16_t sysinterval_t;
|
|
typedef uint32_t time_conv_t;
|
|
#endif
|
|
|
|
/**
|
|
* @brief Type of a structure representing a thread.
|
|
* @note It is required as an early definition.
|
|
*/
|
|
typedef struct nil_thread thread_t;
|
|
|
|
#include "chcore.h"
|
|
|
|
/**
|
|
* @brief Structure representing a queue of threads.
|
|
*/
|
|
struct nil_threads_queue {
|
|
volatile cnt_t cnt; /**< @brief Threads Queue counter. */
|
|
};
|
|
|
|
/**
|
|
* @brief Type of a queue of threads.
|
|
*/
|
|
typedef struct nil_threads_queue threads_queue_t;
|
|
|
|
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief Type of a structure representing a semaphore.
|
|
* @note Semaphores are implemented on thread queues, the object is the
|
|
* same, the behavior is slightly different.
|
|
*/
|
|
typedef threads_queue_t semaphore_t;
|
|
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
|
|
|
/**
|
|
* @brief Thread function.
|
|
*/
|
|
typedef void (*tfunc_t)(void *p);
|
|
|
|
/**
|
|
* @brief Type of a structure representing a thread static configuration.
|
|
*/
|
|
typedef struct nil_thread_cfg thread_config_t;
|
|
|
|
/**
|
|
* @brief Structure representing a thread static configuration.
|
|
*/
|
|
struct nil_thread_cfg {
|
|
stkalign_t *wbase; /**< @brief Thread working area base. */
|
|
stkalign_t *wend; /**< @brief Thread working area end. */
|
|
const char *namep; /**< @brief Thread name, for debugging. */
|
|
tfunc_t funcp; /**< @brief Thread function. */
|
|
void *arg; /**< @brief Thread function argument. */
|
|
};
|
|
|
|
/**
|
|
* @brief Type of a thread reference.
|
|
*/
|
|
typedef thread_t * thread_reference_t;
|
|
|
|
/**
|
|
* @brief Structure representing a thread.
|
|
*/
|
|
struct nil_thread {
|
|
struct port_context ctx; /**< @brief Processor context. */
|
|
tstate_t state; /**< @brief Thread state. */
|
|
/* Note, the following union contains a pointer while the thread is in a
|
|
sleeping state (!NIL_THD_IS_READY()) else contains the wake-up message.*/
|
|
union {
|
|
msg_t msg; /**< @brief Wake-up message. */
|
|
void *p; /**< @brief Generic pointer. */
|
|
thread_reference_t *trp; /**< @brief Pointer to thread reference.*/
|
|
threads_queue_t *tqp; /**< @brief Pointer to thread queue. */
|
|
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
|
semaphore_t *semp; /**< @brief Pointer to semaphore. */
|
|
#endif
|
|
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
|
eventmask_t ewmask; /**< @brief Enabled events mask. */
|
|
#endif
|
|
} u1;
|
|
volatile sysinterval_t timeout; /**< @brief Timeout counter, zero
|
|
if disabled. */
|
|
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
|
eventmask_t epmask; /**< @brief Pending events mask. */
|
|
#endif
|
|
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
|
stkalign_t *wabase; /**< @brief Thread stack boundary. */
|
|
#endif
|
|
/* Optional extra fields.*/
|
|
CH_CFG_THREAD_EXT_FIELDS
|
|
};
|
|
|
|
/**
|
|
* @brief Type of a structure representing the system.
|
|
*/
|
|
typedef struct nil_system nil_system_t;
|
|
|
|
/**
|
|
* @brief System data structure.
|
|
* @note This structure contain all the data areas used by the OS except
|
|
* stacks.
|
|
*/
|
|
struct nil_system {
|
|
/**
|
|
* @brief Pointer to the running thread.
|
|
*/
|
|
thread_t *current;
|
|
/**
|
|
* @brief Pointer to the next thread to be executed.
|
|
* @note This pointer must point at the same thread pointed by @p current
|
|
* or to an higher priority thread if a switch is required.
|
|
*/
|
|
thread_t *next;
|
|
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief System time.
|
|
*/
|
|
volatile systime_t systime;
|
|
#endif
|
|
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief System time of the last tick event.
|
|
*/
|
|
systime_t lasttime;
|
|
/**
|
|
* @brief Time of the next scheduled tick event.
|
|
*/
|
|
systime_t nexttime;
|
|
#endif
|
|
#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief ISR nesting level.
|
|
*/
|
|
cnt_t isr_cnt;
|
|
/**
|
|
* @brief Lock nesting level.
|
|
*/
|
|
cnt_t lock_cnt;
|
|
#endif
|
|
#if (NIL_DBG_ENABLED == TRUE) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief Panic message.
|
|
* @note This field is only present if some debug options have been
|
|
* activated.
|
|
* @note Accesses to this pointer must never be optimized out so the
|
|
* field itself is declared volatile.
|
|
*/
|
|
const char * volatile dbg_panic_msg;
|
|
#endif
|
|
/**
|
|
* @brief Thread structures for all the defined threads.
|
|
*/
|
|
thread_t threads[CH_CFG_NUM_THREADS + 1];
|
|
};
|
|
|
|
/*===========================================================================*/
|
|
/* Module macros. */
|
|
/*===========================================================================*/
|
|
|
|
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
|
#define _dbg_enter_lock() (nil.lock_cnt = (cnt_t)1)
|
|
#define _dbg_leave_lock() (nil.lock_cnt = (cnt_t)0)
|
|
#endif
|
|
|
|
/**
|
|
* @brief Utility to make the parameter a quoted string.
|
|
*/
|
|
#define __CH_STRINGIFY(a) #a
|
|
|
|
/**
|
|
* @name Threads tables definition macros
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Start of user threads table.
|
|
*/
|
|
#define THD_TABLE_BEGIN \
|
|
const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1] = {
|
|
|
|
/**
|
|
* @brief Entry of user threads table
|
|
*/
|
|
#define THD_TABLE_ENTRY(wap, name, funcp, arg) \
|
|
{wap, ((stkalign_t *)(wap)) + (sizeof (wap) / sizeof(stkalign_t)), \
|
|
name, funcp, arg},
|
|
|
|
/**
|
|
* @brief End of user threads table.
|
|
*/
|
|
#define THD_TABLE_END \
|
|
{THD_IDLE_BASE, THD_IDLE_END, "idle", NULL, NULL} \
|
|
};
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Memory alignment support macros
|
|
*/
|
|
/**
|
|
* @brief Alignment mask constant.
|
|
*
|
|
* @param[in] a alignment, must be a power of two
|
|
*/
|
|
#define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U)
|
|
|
|
/**
|
|
* @brief Aligns to the previous aligned memory address.
|
|
*
|
|
* @param[in] p variable to be aligned
|
|
* @param[in] a alignment, must be a power of two
|
|
*/
|
|
#define MEM_ALIGN_PREV(p, a) ((size_t)(p) & ~MEM_ALIGN_MASK(a))
|
|
|
|
/**
|
|
* @brief Aligns to the new aligned memory address.
|
|
*
|
|
* @param[in] p variable to be aligned
|
|
* @param[in] a alignment, must be a power of two
|
|
*/
|
|
#define MEM_ALIGN_NEXT(p, a) MEM_ALIGN_PREV((size_t)(p) + \
|
|
MEM_ALIGN_MASK(a), (a))
|
|
|
|
/**
|
|
* @brief Returns whatever a pointer or memory size is aligned.
|
|
*
|
|
* @param[in] p variable to be aligned
|
|
* @param[in] a alignment, must be a power of two
|
|
*/
|
|
#define MEM_IS_ALIGNED(p, a) (((size_t)(p) & MEM_ALIGN_MASK(a)) == 0U)
|
|
|
|
/**
|
|
* @brief Returns whatever a constant is a valid alignment.
|
|
* @details Valid alignments are powers of two.
|
|
*
|
|
* @param[in] a alignment to be checked, must be a constant
|
|
*/
|
|
#define MEM_IS_VALID_ALIGNMENT(a) \
|
|
(((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U))
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Working Areas
|
|
*/
|
|
/**
|
|
* @brief Calculates the total Working Area size.
|
|
*
|
|
* @param[in] n the stack size to be assigned to the thread
|
|
* @return The total used memory in bytes.
|
|
*
|
|
* @api
|
|
*/
|
|
#define THD_WORKING_AREA_SIZE(n) MEM_ALIGN_NEXT(PORT_WA_SIZE(n), \
|
|
PORT_STACK_ALIGN)
|
|
|
|
/**
|
|
* @brief Static working area allocation.
|
|
* @details This macro is used to allocate a static thread working area
|
|
* aligned as both position and size.
|
|
*
|
|
* @param[in] s the name to be assigned to the stack array
|
|
* @param[in] n the stack size to be assigned to the thread
|
|
*
|
|
* @api
|
|
*/
|
|
#define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Threads abstraction macros
|
|
*/
|
|
/**
|
|
* @brief Thread declaration macro.
|
|
* @note Thread declarations should be performed using this macro because
|
|
* the port layer could define optimizations for thread functions.
|
|
*/
|
|
#define THD_FUNCTION(tname, arg) PORT_THD_FUNCTION(tname, arg)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name ISRs abstraction macros
|
|
*/
|
|
/**
|
|
* @brief Priority level validation macro.
|
|
* @details This macro determines if the passed value is a valid priority
|
|
* level for the underlying architecture.
|
|
*
|
|
* @param[in] prio the priority level
|
|
* @return Priority range result.
|
|
* @retval false if the priority is invalid or if the architecture
|
|
* does not support priorities.
|
|
* @retval true if the priority is valid.
|
|
*/
|
|
#if defined(PORT_IRQ_IS_VALID_PRIORITY) || defined(__DOXYGEN__)
|
|
#define CH_IRQ_IS_VALID_PRIORITY(prio) \
|
|
PORT_IRQ_IS_VALID_PRIORITY(prio)
|
|
#else
|
|
#define CH_IRQ_IS_VALID_PRIORITY(prio) false
|
|
#endif
|
|
|
|
/**
|
|
* @brief Priority level validation macro.
|
|
* @details This macro determines if the passed value is a valid priority
|
|
* level that cannot preempt the kernel critical zone.
|
|
*
|
|
* @param[in] prio the priority level
|
|
* @return Priority range result.
|
|
* @retval false if the priority is invalid or if the architecture
|
|
* does not support priorities.
|
|
* @retval true if the priority is valid.
|
|
*/
|
|
#if defined(PORT_IRQ_IS_VALID_KERNEL_PRIORITY) || defined(__DOXYGEN__)
|
|
#define CH_IRQ_IS_VALID_KERNEL_PRIORITY(prio) \
|
|
PORT_IRQ_IS_VALID_KERNEL_PRIORITY(prio)
|
|
#else
|
|
#define CH_IRQ_IS_VALID_KERNEL_PRIORITY(prio) false
|
|
#endif
|
|
|
|
/**
|
|
* @brief IRQ handler enter code.
|
|
* @note Usually IRQ handlers functions are also declared naked.
|
|
* @note On some architectures this macro can be empty.
|
|
*
|
|
* @special
|
|
*/
|
|
#define CH_IRQ_PROLOGUE() \
|
|
PORT_IRQ_PROLOGUE(); \
|
|
_dbg_check_enter_isr()
|
|
|
|
/**
|
|
* @brief IRQ handler exit code.
|
|
* @note Usually IRQ handlers function are also declared naked.
|
|
*
|
|
* @special
|
|
*/
|
|
#define CH_IRQ_EPILOGUE() \
|
|
_dbg_check_leave_isr(); \
|
|
PORT_IRQ_EPILOGUE()
|
|
|
|
/**
|
|
* @brief Standard normal IRQ handler declaration.
|
|
* @note @p id can be a function name or a vector number depending on the
|
|
* port implementation.
|
|
*
|
|
* @special
|
|
*/
|
|
#define CH_IRQ_HANDLER(id) PORT_IRQ_HANDLER(id)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Fast ISRs abstraction macros
|
|
*/
|
|
/**
|
|
* @brief Standard fast IRQ handler declaration.
|
|
* @note @p id can be a function name or a vector number depending on the
|
|
* port implementation.
|
|
* @note Not all architectures support fast interrupts.
|
|
*
|
|
* @special
|
|
*/
|
|
#define CH_FAST_IRQ_HANDLER(id) PORT_FAST_IRQ_HANDLER(id)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Time conversion utilities
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Seconds to time interval.
|
|
* @details Converts from seconds to system ticks number.
|
|
* @note The result is rounded upward to the next tick boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] secs number of seconds
|
|
* @return The number of ticks.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_S2I(secs) \
|
|
((sysinterval_t)((time_conv_t)(secs) * (time_conv_t)CH_CFG_ST_FREQUENCY))
|
|
|
|
/**
|
|
* @brief Milliseconds to time interval.
|
|
* @details Converts from milliseconds to system ticks number.
|
|
* @note The result is rounded upward to the next tick boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] msecs number of milliseconds
|
|
* @return The number of ticks.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_MS2I(msecs) \
|
|
((sysinterval_t)((((time_conv_t)(msecs) * \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY) + \
|
|
(time_conv_t)999) / (time_conv_t)1000))
|
|
|
|
/**
|
|
* @brief Microseconds to time interval.
|
|
* @details Converts from microseconds to system ticks number.
|
|
* @note The result is rounded upward to the next tick boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] usecs number of microseconds
|
|
* @return The number of ticks.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_US2I(usecs) \
|
|
((sysinterval_t)((((time_conv_t)(usecs) * \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY) + \
|
|
(time_conv_t)999999) / (time_conv_t)1000000))
|
|
|
|
/**
|
|
* @brief Time interval to seconds.
|
|
* @details Converts from system ticks number to seconds.
|
|
* @note The result is rounded up to the next second boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] interval interval in ticks
|
|
* @return The number of seconds.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_I2S(interval) \
|
|
(time_secs_t)(((time_conv_t)(interval) + \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY - \
|
|
(time_conv_t)1) / (time_conv_t)CH_CFG_ST_FREQUENCY)
|
|
|
|
/**
|
|
* @brief Time interval to milliseconds.
|
|
* @details Converts from system ticks number to milliseconds.
|
|
* @note The result is rounded up to the next millisecond boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] interval interval in ticks
|
|
* @return The number of milliseconds.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_I2MS(interval) \
|
|
(time_msecs_t)((((time_conv_t)(interval) * (time_conv_t)1000) + \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY - (time_conv_t)1) / \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY)
|
|
|
|
/**
|
|
* @brief Time interval to microseconds.
|
|
* @details Converts from system ticks number to microseconds.
|
|
* @note The result is rounded up to the next microsecond boundary.
|
|
* @note Use of this macro for large values is not secure because
|
|
* integer overflows, make sure your value can be correctly
|
|
* converted.
|
|
*
|
|
* @param[in] interval interval in ticks
|
|
* @return The number of microseconds.
|
|
*
|
|
* @api
|
|
*/
|
|
#define TIME_I2US(interval) \
|
|
(time_msecs_t)((((time_conv_t)(interval) * (time_conv_t)1000000) + \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY - (time_conv_t)1) / \
|
|
(time_conv_t)CH_CFG_ST_FREQUENCY)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Threads queues
|
|
*/
|
|
/**
|
|
* @brief Data part of a static threads queue object initializer.
|
|
* @details This macro should be used when statically initializing a threads
|
|
* queue that is part of a bigger structure.
|
|
*
|
|
* @param[in] name the name of the threads queue variable
|
|
*/
|
|
#define _THREADS_QUEUE_DATA(name) {(cnt_t)0}
|
|
|
|
/**
|
|
* @brief Static threads queue object initializer.
|
|
* @details Statically initialized threads queues require no explicit
|
|
* initialization using @p queue_init().
|
|
*
|
|
* @param[in] name the name of the threads queue variable
|
|
*/
|
|
#define _THREADS_QUEUE_DECL(name) \
|
|
threads_queue_t name = _THREADS_QUEUE_DATA(name)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Semaphores macros
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Data part of a static semaphore initializer.
|
|
* @details This macro should be used when statically initializing a semaphore
|
|
* that is part of a bigger structure.
|
|
*
|
|
* @param[in] name the name of the semaphore variable
|
|
* @param[in] n the counter initial value, this value must be
|
|
* non-negative
|
|
*/
|
|
#define _SEMAPHORE_DATA(name, n) {n}
|
|
|
|
/**
|
|
* @brief Static semaphore initializer.
|
|
* @details Statically initialized semaphores require no explicit
|
|
* initialization using @p chSemInit().
|
|
*
|
|
* @param[in] name the name of the semaphore variable
|
|
* @param[in] n the counter initial value, this value must be
|
|
* non-negative
|
|
*/
|
|
#define SEMAPHORE_DECL(name, n) semaphore_t name = _SEMAPHORE_DATA(name, n)
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Macro Functions
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Returns the current value of the system real time counter.
|
|
* @note This function is only available if the port layer supports the
|
|
* option @p PORT_SUPPORTS_RT.
|
|
*
|
|
* @return The value of the system realtime counter of
|
|
* type rtcnt_t.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__)
|
|
#define chSysGetRealtimeCounterX() (rtcnt_t)port_rt_get_counter_value()
|
|
#endif
|
|
|
|
/**
|
|
* @brief Raises the system interrupt priority mask to the maximum level.
|
|
* @details All the maskable interrupt sources are disabled regardless their
|
|
* hardware priority.
|
|
* @note Do not invoke this API from within a kernel lock.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysDisable() { \
|
|
port_disable(); \
|
|
_dbg_check_disable(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Raises the system interrupt priority mask to system level.
|
|
* @details The interrupt sources that should not be able to preempt the kernel
|
|
* are disabled, interrupt sources with higher priority are still
|
|
* enabled.
|
|
* @note Do not invoke this API from within a kernel lock.
|
|
* @note This API is no replacement for @p chSysLock(), the @p chSysLock()
|
|
* could do more than just disable the interrupts.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysSuspend() { \
|
|
port_suspend(); \
|
|
_dbg_check_suspend(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Lowers the system interrupt priority mask to user level.
|
|
* @details All the interrupt sources are enabled.
|
|
* @note Do not invoke this API from within a kernel lock.
|
|
* @note This API is no replacement for @p chSysUnlock(), the
|
|
* @p chSysUnlock() could do more than just enable the interrupts.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysEnable() { \
|
|
_dbg_check_enable(); \
|
|
port_enable(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Enters the kernel lock state.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysLock() { \
|
|
port_lock(); \
|
|
_dbg_check_lock(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Leaves the kernel lock state.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysUnlock() { \
|
|
_dbg_check_unlock(); \
|
|
port_unlock(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Enters the kernel lock state from within an interrupt handler.
|
|
* @note This API may do nothing on some architectures, it is required
|
|
* because on ports that support preemptable interrupt handlers
|
|
* it is required to raise the interrupt mask to the same level of
|
|
* the system mutual exclusion zone.<br>
|
|
* It is good practice to invoke this API before invoking any I-class
|
|
* syscall from an interrupt handler.
|
|
* @note This API must be invoked exclusively from interrupt handlers.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysLockFromISR() { \
|
|
port_lock_from_isr(); \
|
|
_dbg_check_lock_from_isr(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Leaves the kernel lock state from within an interrupt handler.
|
|
*
|
|
* @note This API may do nothing on some architectures, it is required
|
|
* because on ports that support preemptable interrupt handlers
|
|
* it is required to raise the interrupt mask to the same level of
|
|
* the system mutual exclusion zone.<br>
|
|
* It is good practice to invoke this API after invoking any I-class
|
|
* syscall from an interrupt handler.
|
|
* @note This API must be invoked exclusively from interrupt handlers.
|
|
*
|
|
* @special
|
|
*/
|
|
#define chSysUnlockFromISR() { \
|
|
_dbg_check_unlock_from_isr(); \
|
|
port_unlock_from_isr(); \
|
|
}
|
|
|
|
/**
|
|
* @brief Evaluates if a reschedule is required.
|
|
*
|
|
* @retval true if there is a thread that must go in running state
|
|
* immediately.
|
|
* @retval false if preemption is not required.
|
|
*
|
|
* @iclass
|
|
*/
|
|
#define chSchIsRescRequiredI() ((bool)(nil.current != nil.next))
|
|
|
|
/**
|
|
* @brief Returns a pointer to the current @p thread_t.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#define chThdGetSelfX() nil.current
|
|
|
|
/**
|
|
* @brief Delays the invoking thread for the specified number of seconds.
|
|
* @note The specified time is rounded up to a value allowed by the real
|
|
* system clock.
|
|
* @note The maximum specified value is implementation dependent.
|
|
*
|
|
* @param[in] secs time in seconds, must be different from zero
|
|
*
|
|
* @api
|
|
*/
|
|
#define chThdSleepSeconds(secs) chThdSleep(TIME_S2I(secs))
|
|
|
|
/**
|
|
* @brief Delays the invoking thread for the specified number of
|
|
* milliseconds.
|
|
* @note The specified time is rounded up to a value allowed by the real
|
|
* system clock.
|
|
* @note The maximum specified value is implementation dependent.
|
|
*
|
|
* @param[in] msecs time in milliseconds, must be different from zero
|
|
*
|
|
* @api
|
|
*/
|
|
#define chThdSleepMilliseconds(msecs) chThdSleep(TIME_MS2I(msecs))
|
|
|
|
/**
|
|
* @brief Delays the invoking thread for the specified number of
|
|
* microseconds.
|
|
* @note The specified time is rounded up to a value allowed by the real
|
|
* system clock.
|
|
* @note The maximum specified value is implementation dependent.
|
|
*
|
|
* @param[in] usecs time in microseconds, must be different from zero
|
|
*
|
|
* @api
|
|
*/
|
|
#define chThdSleepMicroseconds(usecs) chThdSleep(TIME_US2I(usecs))
|
|
|
|
/**
|
|
* @brief Suspends the invoking thread for the specified time.
|
|
*
|
|
* @param[in] timeout the delay in system ticks
|
|
*
|
|
* @sclass
|
|
*/
|
|
#define chThdSleepS(timeout) \
|
|
(void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, timeout)
|
|
|
|
/**
|
|
* @brief Suspends the invoking thread until the system time arrives to the
|
|
* specified value.
|
|
*
|
|
* @param[in] abstime absolute system time
|
|
*
|
|
* @sclass
|
|
*/
|
|
#define chThdSleepUntilS(abstime) \
|
|
(void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, \
|
|
chTimeDiffX(chVTGetSystemTimeX(), (abstime)))
|
|
|
|
/**
|
|
* @brief Initializes a threads queue object.
|
|
*
|
|
* @param[out] tqp pointer to the threads queue object
|
|
*
|
|
* @init
|
|
*/
|
|
#define chThdQueueObjectInit(tqp) ((tqp)->cnt = (cnt_t)0)
|
|
|
|
/**
|
|
* @brief Evaluates to @p true if the specified queue is empty.
|
|
*
|
|
* @param[out] tqp pointer to the threads queue object
|
|
* @return The queue status.
|
|
* @retval false if the queue is not empty.
|
|
* @retval true if the queue is empty.
|
|
*
|
|
* @iclass
|
|
*/
|
|
#define chThdQueueIsEmptyI(tqp) ((bool)(tqp->cnt >= (cnt_t)0))
|
|
|
|
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
|
/**
|
|
* @brief Initializes a semaphore with the specified counter value.
|
|
*
|
|
* @param[out] sp pointer to a @p semaphore_t structure
|
|
* @param[in] n initial value of the semaphore counter. Must be
|
|
* non-negative.
|
|
*
|
|
* @init
|
|
*/
|
|
#define chSemObjectInit(sp, n) ((sp)->cnt = (n))
|
|
|
|
/**
|
|
* @brief Performs a wait operation on a semaphore.
|
|
*
|
|
* @param[in] sp pointer to a @p semaphore_t structure
|
|
* @return A message specifying how the invoking thread has been
|
|
* released from the semaphore.
|
|
* @retval CH_MSG_OK if the thread has not stopped on the semaphore or the
|
|
* semaphore has been signaled.
|
|
* @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset().
|
|
*
|
|
* @api
|
|
*/
|
|
#define chSemWait(sp) chSemWaitTimeout(sp, TIME_INFINITE)
|
|
|
|
/**
|
|
* @brief Performs a wait operation on a semaphore.
|
|
*
|
|
* @param[in] sp pointer to a @p semaphore_t structure
|
|
* @return A message specifying how the invoking thread has been
|
|
* released from the semaphore.
|
|
* @retval CH_MSG_OK if the thread has not stopped on the semaphore or the
|
|
* semaphore has been signaled.
|
|
* @retval CH_MSG_RST if the semaphore has been reset using @p chSemReset().
|
|
*
|
|
* @sclass
|
|
*/
|
|
#define chSemWaitS(sp) chSemWaitTimeoutS(sp, TIME_INFINITE)
|
|
|
|
/**
|
|
* @brief Decreases the semaphore counter.
|
|
* @details This macro can be used when the counter is known to be positive.
|
|
*
|
|
* @param[in] sp pointer to a @p semaphore_t structure
|
|
*
|
|
* @iclass
|
|
*/
|
|
#define chSemFastWaitI(sp) ((sp)->cnt--)
|
|
|
|
/**
|
|
* @brief Increases the semaphore counter.
|
|
* @details This macro can be used when the counter is known to be not
|
|
* negative.
|
|
*
|
|
* @param[in] sp pointer to a @p semaphore_t structure
|
|
*
|
|
* @iclass
|
|
*/
|
|
#define chSemFastSignalI(sp) ((sp)->cnt++)
|
|
|
|
/**
|
|
* @brief Returns the semaphore counter current value.
|
|
*
|
|
* @iclass
|
|
*/
|
|
#define chSemGetCounterI(sp) ((sp)->cnt)
|
|
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
|
|
|
/**
|
|
* @brief Current system time.
|
|
* @details Returns the number of system ticks since the @p chSysInit()
|
|
* invocation.
|
|
* @note The counter can reach its maximum and then restart from zero.
|
|
* @note This function can be called from any context but its atomicity
|
|
* is not guaranteed on architectures whose word size is less than
|
|
* @p systime_t size.
|
|
*
|
|
* @return The system time in ticks.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
|
#define chVTGetSystemTimeX() (nil.systime)
|
|
#else
|
|
#define chVTGetSystemTimeX() port_timer_get_time()
|
|
#endif
|
|
|
|
/**
|
|
* @brief Returns the elapsed time since the specified start time.
|
|
*
|
|
* @param[in] start start time
|
|
* @return The elapsed time.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#define chVTTimeElapsedSinceX(start) \
|
|
chTimeDiffX((start), chVTGetSystemTimeX())
|
|
|
|
/**
|
|
* @brief Adds an interval to a system time returning a system time.
|
|
*
|
|
* @param[in] systime base system time
|
|
* @param[in] interval interval to be added
|
|
* @return The new system time.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#define chTimeAddX(systime, interval) \
|
|
((systime_t)(systime) + (systime_t)(interval))
|
|
|
|
/**
|
|
* @brief Subtracts two system times returning an interval.
|
|
*
|
|
* @param[in] start first system time
|
|
* @param[in] end second system time
|
|
* @return The interval representing the time difference.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#define chTimeDiffX(start, end) \
|
|
((sysinterval_t)((systime_t)((systime_t)(end) - (systime_t)(start))))
|
|
|
|
/**
|
|
* @brief Checks if the specified time is within the specified time range.
|
|
* @note When start==end then the function returns always true because the
|
|
* whole time range is specified.
|
|
*
|
|
* @param[in] time the time to be verified
|
|
* @param[in] start the start of the time window (inclusive)
|
|
* @param[in] end the end of the time window (non inclusive)
|
|
* @retval true current time within the specified time window.
|
|
* @retval false current time not within the specified time window.
|
|
*
|
|
* @xclass
|
|
*/
|
|
#define chTimeIsInRangeX(time, start, end) \
|
|
((bool)((systime_t)((systime_t)(time) - (systime_t)(start)) < \
|
|
(systime_t)((systime_t)(end) - (systime_t)(start))))
|
|
|
|
/**
|
|
* @brief Function parameters check.
|
|
* @details If the condition check fails then the kernel panics and halts.
|
|
* @note The condition is tested only if the @p CH_DBG_ENABLE_CHECKS switch
|
|
* is specified in @p chconf.h else the macro does nothing.
|
|
*
|
|
* @param[in] c the condition to be verified to be true
|
|
*
|
|
* @api
|
|
*/
|
|
#if !defined(chDbgCheck)
|
|
#define chDbgCheck(c) do { \
|
|
/*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \
|
|
if (CH_DBG_ENABLE_CHECKS != FALSE) { \
|
|
if (!(c)) { \
|
|
/*lint -restore*/ \
|
|
chSysHalt(__func__); \
|
|
} \
|
|
} \
|
|
} while (false)
|
|
#endif /* !defined(chDbgCheck) */
|
|
|
|
/**
|
|
* @brief Condition assertion.
|
|
* @details If the condition check fails then the kernel panics with a
|
|
* message and halts.
|
|
* @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS
|
|
* switch is specified in @p chconf.h else the macro does nothing.
|
|
* @note The remark string is not currently used except for putting a
|
|
* comment in the code about the assertion.
|
|
*
|
|
* @param[in] c the condition to be verified to be true
|
|
* @param[in] r a remark string
|
|
*
|
|
* @api
|
|
*/
|
|
#if !defined(chDbgAssert)
|
|
#define chDbgAssert(c, r) do { \
|
|
/*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \
|
|
if (CH_DBG_ENABLE_ASSERTS != FALSE) { \
|
|
if (!(c)) { \
|
|
/*lint -restore*/ \
|
|
chSysHalt(__func__); \
|
|
} \
|
|
} \
|
|
} while (false)
|
|
#endif /* !defined(chDbgAssert) */
|
|
/** @} */
|
|
|
|
/* Empty macros if the state checker is not enabled.*/
|
|
#if CH_DBG_SYSTEM_STATE_CHECK == FALSE
|
|
#define _dbg_enter_lock()
|
|
#define _dbg_leave_lock()
|
|
#define _dbg_check_disable()
|
|
#define _dbg_check_suspend()
|
|
#define _dbg_check_enable()
|
|
#define _dbg_check_lock()
|
|
#define _dbg_check_unlock()
|
|
#define _dbg_check_lock_from_isr()
|
|
#define _dbg_check_unlock_from_isr()
|
|
#define _dbg_check_enter_isr()
|
|
#define _dbg_check_leave_isr()
|
|
#define chDbgCheckClassI()
|
|
#define chDbgCheckClassS()
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* External declarations. */
|
|
/*===========================================================================*/
|
|
|
|
#if !defined(__DOXYGEN__)
|
|
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
|
extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__;
|
|
#endif
|
|
extern nil_system_t nil;
|
|
extern const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1];
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
void chSysInit(void);
|
|
void chSysHalt(const char *reason);
|
|
void chSysTimerHandlerI(void);
|
|
void chSysUnconditionalLock(void);
|
|
void chSysUnconditionalUnlock(void);
|
|
syssts_t chSysGetStatusAndLockX(void);
|
|
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end);
|
|
void chSysPolledDelayX(rtcnt_t cycles);
|
|
void chSysRestoreStatusX(syssts_t sts);
|
|
thread_t *chSchReadyI(thread_t *tp, msg_t msg);
|
|
bool chSchIsPreemptionRequired(void);
|
|
void chSchDoReschedule(void);
|
|
void chSchRescheduleS(void);
|
|
msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout);
|
|
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout);
|
|
void chThdResumeI(thread_reference_t *trp, msg_t msg);
|
|
void chThdResume(thread_reference_t *trp, msg_t msg);
|
|
void chThdSleep(sysinterval_t timeout);
|
|
void chThdSleepUntil(systime_t abstime);
|
|
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout);
|
|
void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg);
|
|
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg);
|
|
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg);
|
|
#if CH_CFG_USE_SEMAPHORES == TRUE
|
|
msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout);
|
|
msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_t timeout);
|
|
void chSemSignal(semaphore_t *sp);
|
|
void chSemSignalI(semaphore_t *sp);
|
|
void chSemReset(semaphore_t *sp, cnt_t n);
|
|
void chSemResetI(semaphore_t *sp, cnt_t n);
|
|
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
|
#if CH_CFG_USE_EVENTS == TRUE
|
|
void chEvtSignal(thread_t *tp, eventmask_t mask);
|
|
void chEvtSignalI(thread_t *tp, eventmask_t mask);
|
|
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout);
|
|
#endif
|
|
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
|
void _dbg_check_disable(void);
|
|
void _dbg_check_suspend(void);
|
|
void _dbg_check_enable(void);
|
|
void _dbg_check_lock(void);
|
|
void _dbg_check_unlock(void);
|
|
void _dbg_check_lock_from_isr(void);
|
|
void _dbg_check_unlock_from_isr(void);
|
|
void _dbg_check_enter_isr(void);
|
|
void _dbg_check_leave_isr(void);
|
|
void chDbgCheckClassI(void);
|
|
void chDbgCheckClassS(void);
|
|
#endif
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/* OSLIB.*/
|
|
#include "chlib.h"
|
|
|
|
#endif /* CH_H */
|
|
|
|
/** @} */
|