/*
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 .
*/
/**
* @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"
/*===========================================================================*/
/* 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 "4.0.0"
/**
* @brief Kernel version major number.
*/
#define CH_KERNEL_MAJOR 4
/**
* @brief Kernel version minor number.
*/
#define CH_KERNEL_MINOR 0
/**
* @brief Kernel version patch number.
*/
#define CH_KERNEL_PATCH 0
/** @} */
/**
* @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_WTSTART (tstate_t)0 /**< @brief Thread not yet
started or terminated. */
#define NIL_STATE_READY (tstate_t)1 /**< @brief Thread ready or
executing. */
#define NIL_STATE_SLEEPING (tstate_t)2 /**< @brief Thread sleeping. */
#define NIL_STATE_SUSPENDED (tstate_t)3 /**< @brief Thread suspended. */
#define NIL_STATE_WTEXIT (tstate_t)4 /**< @brief Waiting a thread. */
#define NIL_STATE_WTQUEUE (tstate_t)5 /**< @brief On queue or semaph. */
#define NIL_STATE_WTOREVT (tstate_t)6 /**< @brief Waiting for events. */
#define NIL_STATE_WTANDEVT (tstate_t)7 /**< @brief Waiting for events. */
#define NIL_STATE_SNDMSGQ (tstate_t)8 /**< @brief Sending a message,
in queue. */
#define NIL_STATE_WTMSG (tstate_t)10/**< @brief Waiting for a
message. */
#define NIL_STATE_FINAL (tstate_t)11/**< @brief Thread terminated. */
#define NIL_THD_IS_WTSTART(tp) ((tp)->state == NIL_STATE_WTSTART)
#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_SUSPENDED(tp) ((tp)->state == NIL_STATE_SUSPENDED)
#define NIL_THD_IS_WTEXIT(tp) ((tp)->state == NIL_STATE_WTEXIT)
#define NIL_THD_IS_WTQUEUE(tp) ((tp)->state == NIL_STATE_WTQUEUE)
#define NIL_THD_IS_WTOREVT(tp) ((tp)->state == NIL_STATE_WTOREVT)
#define NIL_THD_IS_WTANDEVT(tp) ((tp)->state == NIL_STATE_WTANDEVT)
#define NIL_THD_IS_SNDMSGQ(tp) ((tp)->state == NIL_STATE_SNDMSGQ)
#define NIL_THD_IS_WTMSG(tp) ((tp)->state == NIL_STATE_WTMSG)
#define NIL_THD_IS_FINAL(tp) ((tp)->state == NIL_STATE_FINAL)
#define CH_STATE_NAMES \
"WTSTART", "READY", "SLEEPING", "SUSPENDED", "WTEXIT", "WTQUEUE", \
"WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL"
/** @} */
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
#include "chconf.h"
#include "chlicense.h"
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/* Checks on configuration options.*/
#if !defined(CH_CFG_MAX_THREADS) || defined(__DOXYGEN__)
#error "CH_CFG_MAX_THREADS not defined in chconf.h"
#endif
#if !defined(CH_CFG_AUTOSTART_THREADS) || defined(__DOXYGEN__)
#error "CH_CFG_AUTOSTART_THREADS not defined in chconf.h"
#endif
#if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__)
#error "CH_CFG_ST_RESOLUTION not defined in chconf.h"
#endif
#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__)
#error "CH_CFG_ST_FREQUENCY not defined in chconf.h"
#endif
#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__)
#error "CH_CFG_ST_TIMEDELTA not defined in chconf.h"
#endif
#if !defined(CH_CFG_USE_WAITEXIT)
#error "CH_CFG_USE_WAITEXIT not defined in chconf.h"
#endif
#if !defined(CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
#error "CH_CFG_USE_MESSAGES not defined in chconf.h"
#endif
#if !defined(CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
#error "CH_CFG_USE_SEMAPHORES not defined in chconf.h"
#endif
#if !defined(CH_CFG_USE_EVENTS)
#error "CH_CFG_USE_EVENTS not defined in chconf.h"
#endif
#if !defined(CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
#error "CH_CFG_USE_MUTEXES not defined in chconf.h"
#endif
#if !defined(CH_DBG_STATISTICS) || defined(__DOXYGEN__)
#error "CH_DBG_STATISTICS not defined in chconf.h"
#endif
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
#error "CH_DBG_SYSTEM_STATE_CHECK not defined in chconf.h"
#endif
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
#error "CH_DBG_ENABLE_CHECKS not defined in chconf.h"
#endif
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
#error "CH_DBG_ENABLE_ASSERTS not defined in chconf.h"
#endif
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
#error "CH_DBG_ENABLE_STACK_CHECK not defined in chconf.h"
#endif
#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_SYSTEM_INIT_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
#error "CH_CFG_THREAD_EXT_FIELDS not defined in chconf.h"
#endif
#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_THREAD_EXT_INIT_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_THREAD_EXIT_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_THREAD_EXIT_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_IDLE_ENTER_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_IDLE_LEAVE_HOOK not defined in chconf.h"
#endif
#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
#error "CH_CFG_SYSTEM_HALT_HOOK not defined in chconf.h"
#endif
/* 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
/* Messages restricted.*/
#undef CH_CFG_USE_MESSAGES
#define CH_CFG_USE_MESSAGES FALSE
#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_4_0_)
#error "obsolete or unknown configuration file"
#endif
#if CH_CFG_MAX_THREADS < 1
#error "at least one thread must be defined"
#endif
#if CH_CFG_MAX_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 the system.
*/
typedef struct nil_system nil_system_t;
/**
* @brief Thread function.
*/
typedef void (*tfunc_t)(void *p);
/**
* @brief Type of a thread descriptor.
*/
typedef struct nil_thread_descriptor thread_descriptor_t;
/**
* @brief Type of a structure representing a thread.
* @note It is required as an early definition.
*/
typedef struct nil_thread thread_t;
/**
* @brief Type of a thread reference.
*/
typedef thread_t * thread_reference_t;
/**
* @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 */
/* Late inclusion of port core layer.*/
#include "chcore.h"
/**
* @brief Structure representing a queue of threads.
*/
struct nil_threads_queue {
volatile cnt_t cnt; /**< @brief Threads Queue counter. */
};
/**
* @brief Structure representing a thread descriptor.
*/
struct nil_thread_descriptor {
const char *name; /**< @brief Thread name, for debugging. */
stkalign_t *wbase; /**< @brief Thread working area base. */
stkalign_t *wend; /**< @brief Thread working area end. */
tprio_t prio; /**< @brief Thread priority slot. */
tfunc_t funcp; /**< @brief Thread function. */
void *arg; /**< @brief Thread function argument. */
};
/**
* @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/value while the thread is
in a sleeping state or a wake-up message when the thread is made ready.*/
union {
msg_t msg; /**< @brief Wake-up/exit message. */
void *p; /**< @brief Generic pointer. */
nil_system_t *nsp; /**< @brief Pointer to nil base struct. */
thread_reference_t *trp; /**< @brief Pointer to thread reference.*/
threads_queue_t *tqp; /**< @brief Pointer to thread queue. */
thread_t *tp; /**< @brief Pointer to thread. */
#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_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__)
msg_t sntmsg; /**< @brief Sent message. */
#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 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_MAX_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_descriptor_t nil_thd_configs[] = {
/**
* @brief Entry of user threads table
*/
#define THD_TABLE_THREAD(_prio, _name, _wap, _funcp, _arg) \
{ \
.name = (_name), \
.wbase = (_wap), \
.wend = THD_WORKING_AREA_END(_wap), \
.prio = (_prio), \
.funcp = (_funcp), \
.arg = (_arg) \
},
/**
* @brief End of user threads table.
*/
#define THD_TABLE_END \
{ \
.name = "idle", \
.wbase = THD_IDLE_BASE, \
.wend = THD_IDLE_END, \
.prio = CH_CFG_MAX_THREADS, \
.funcp = NULL, \
.arg = 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)
/** @} */
/**
* @brief Returns the top address of a working area.
* @note The parameter is assumed to be an array of @p stkalign_t. The
* macros is invalid for anything else.
*
* @param[in] wa working area array
*
* @api
*/
#define THD_WORKING_AREA_END(wa) \
((wa) + ((sizeof wa) / sizeof (stkalign_t)))
/**
* @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.
* 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.
* 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 Puts the current thread to sleep into the specified state.
*
* @param[in] newstate the new thread state or a semaphore pointer
* @return The wakeup message.
*
* @sclass
*/
#define chSchGoSleepS(newstate) chSchGoSleepTimeoutS(newstate, TIME_INFINITE)
/**
* @brief Wakes up a thread.
*
* @param[in] ntp the thread to be made ready
* @param[in] msg the wakeup message
*
* @sclass
*/
#define chSchWakeupS(ntp, msg) do { \
chSchReadyI(ntp, msg); \
chSchRescheduleS(); \
} while (false)
/**
* @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 Returns the current thread priority.
* @note Can be invoked in any context.
*
* @return The current thread priority.
*
* @xclass
*/
#define chThdGetPriorityX(void) (tprio_t)(nil.current - &nil.threads[0])
/**
* @brief Wakes up a thread waiting on a thread reference object.
* @note This function must reschedule, it can only be called from thread
* context.
*
* @param[in] trp a pointer to a thread reference object
* @param[in] msg the message code
*
* @sclass
*/
#define chThdResumeS(trp, msg) do { \
chThdResumeI(trp, msg); \
chSchRescheduleS(); \
} while (false)
/**
* @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))
/**
* @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 Checks if the current system time is within the specified time
* window.
* @note When start==end then the function returns always false because the
* time window has zero size.
*
* @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 chVTIsSystemTimeWithinX(start, end) \
chTimeIsInRangeX(chVTGetSystemTimeX(), start, end)
/**
* @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 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_descriptor_t nil_thd_configs[];
#endif
#ifdef __cplusplus
extern "C" {
#endif
thread_t *nil_find_thread(tstate_t state, void *p);
cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg);
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);
bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end);
thread_t *chThdCreateI(const thread_descriptor_t *tdp);
thread_t *chThdCreate(const thread_descriptor_t *tdp);
void chThdExit(msg_t msg);
#if CH_CFG_USE_WAITEXIT == TRUE
msg_t chThdWait(thread_t *tp);
#endif
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_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
/* Optional modules.*/
#include "chsem.h"
#include "chevt.h"
#include "chmsg.h"
#include "chlib.h"
#endif /* CH_H */
/** @} */