From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan <clyne@bitgloo.com> Date: Fri, 22 Jan 2021 21:43:36 -0500 Subject: upload initial port --- ChibiOS_20.3.2/os/nil/include/ch.h | 1419 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1419 insertions(+) create mode 100644 ChibiOS_20.3.2/os/nil/include/ch.h (limited to 'ChibiOS_20.3.2/os/nil/include/ch.h') diff --git a/ChibiOS_20.3.2/os/nil/include/ch.h b/ChibiOS_20.3.2/os/nil/include/ch.h new file mode 100644 index 0000000..0e407bf --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/include/ch.h @@ -0,0 +1,1419 @@ +/* + 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" + +/*===========================================================================*/ +/* 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.<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 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 */ + +/** @} */ -- cgit v1.2.3