From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Fri, 22 Jan 2021 21:43:36 -0500 Subject: upload initial port --- ChibiOS_20.3.2/os/nil/dox/nil.dox | 65 ++ ChibiOS_20.3.2/os/nil/include/ch.h | 1419 ++++++++++++++++++++++++++++++ ChibiOS_20.3.2/os/nil/include/chevt.h | 301 +++++++ ChibiOS_20.3.2/os/nil/include/chmsg.h | 123 +++ ChibiOS_20.3.2/os/nil/include/chsem.h | 180 ++++ ChibiOS_20.3.2/os/nil/nil.mk | 42 + ChibiOS_20.3.2/os/nil/src/ch.c | 1080 +++++++++++++++++++++++ ChibiOS_20.3.2/os/nil/src/chevt.c | 478 ++++++++++ ChibiOS_20.3.2/os/nil/src/chmsg.c | 201 +++++ ChibiOS_20.3.2/os/nil/src/chsem.c | 224 +++++ ChibiOS_20.3.2/os/nil/templates/chconf.h | 479 ++++++++++ 11 files changed, 4592 insertions(+) create mode 100644 ChibiOS_20.3.2/os/nil/dox/nil.dox create mode 100644 ChibiOS_20.3.2/os/nil/include/ch.h create mode 100644 ChibiOS_20.3.2/os/nil/include/chevt.h create mode 100644 ChibiOS_20.3.2/os/nil/include/chmsg.h create mode 100644 ChibiOS_20.3.2/os/nil/include/chsem.h create mode 100644 ChibiOS_20.3.2/os/nil/nil.mk create mode 100644 ChibiOS_20.3.2/os/nil/src/ch.c create mode 100644 ChibiOS_20.3.2/os/nil/src/chevt.c create mode 100644 ChibiOS_20.3.2/os/nil/src/chmsg.c create mode 100644 ChibiOS_20.3.2/os/nil/src/chsem.c create mode 100644 ChibiOS_20.3.2/os/nil/templates/chconf.h (limited to 'ChibiOS_20.3.2/os/nil') diff --git a/ChibiOS_20.3.2/os/nil/dox/nil.dox b/ChibiOS_20.3.2/os/nil/dox/nil.dox new file mode 100644 index 0000000..9fd3af5 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/dox/nil.dox @@ -0,0 +1,65 @@ +/* + 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 . +*/ + +/** + * @defgroup NIL NIL Kernel + * @details The kernel is the portable part of ChibiOS/NIL, this section + * documents the various kernel subsystems. + */ + +/** + * @defgroup NIL_CONFIG Configuration + * @ingroup NIL + */ + +/*-* + * @defgroup NIL_TYPES Kernel Types + * @ingroup NIL + */ + +/** + * @defgroup NIL_KERNEL Base API + * @ingroup NIL + */ + +/** + * @defgroup NIL_SEMAPHORES Semaphores + * @ingroup NIL + */ + +/** + * @defgroup NIL_EVENTS Events + * @ingroup NIL + */ + +/** + * @defgroup NIL_MESSAGES Synchronous Messages + * @ingroup NIL + */ + +/*-* + * @defgroup NIL_CORE Port Layer + * @ingroup NIL + */ + +/*-* + * @defgroup NIL_TIMER Timer Interface + * @ingroup NIL + */ + 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 . +*/ + +/** + * @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 */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/include/chevt.h b/ChibiOS_20.3.2/os/nil/include/chevt.h new file mode 100644 index 0000000..7d74461 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/include/chevt.h @@ -0,0 +1,301 @@ +/* + 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/chevt.h + * @brief Nil RTOS events header file. + * + * @addtogroup NIL_EVENTS + * @{ + */ + +#ifndef CHEVT_H +#define CHEVT_H + +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +typedef struct event_listener event_listener_t; + +/** + * @brief Event Listener structure. + */ +struct event_listener { + event_listener_t *next; /**< @brief Next Event Listener + registered on the event + source. */ + thread_t *listener; /**< @brief Thread interested in the + event source. */ + eventmask_t events; /**< @brief Events to be set in + the listening thread. */ + eventflags_t flags; /**< @brief Flags added to the listener + by the event source. */ + eventflags_t wflags; /**< @brief Flags that this listener + interested in. */ +}; + +/** + * @brief Event Source structure. + */ +typedef struct event_source { + event_listener_t *next; /**< @brief First Event Listener + registered on the Event + Source. */ +} event_source_t; + +/** + * @brief Event Handler callback function. + */ +typedef void (*evhandler_t)(eventid_t id); + +/*===========================================================================*/ +/* Module 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 << (eventmask_t)(eid)) + +/** + * @brief Data part of a static event source initializer. + * @details This macro should be used when statically initializing an event + * source that is part of a bigger structure. + * @param name the name of the event source variable + */ +#define _EVENTSOURCE_DATA(name) {(event_listener_t *)(&name)} + +/** + * @brief Static event source initializer. + * @details Statically initialized event sources require no explicit + * initialization using @p chEvtInit(). + * + * @param name the name of the event source variable + */ +#define EVENTSOURCE_DECL(name) event_source_t name = _EVENTSOURCE_DATA(name) + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Initializes an Event Source. + * @note This function can be invoked before the kernel is initialized + * because it just prepares a @p event_source_t structure. + * + * @param[in] esp pointer to the @p event_source_t structure + * + * @init + */ +#define chEvtObjectInit(esp) do { \ + (esp)->next = (event_listener_t *)(esp); \ +} while (0) + +/** + * @brief Registers an Event Listener on an Event Source. + * @details Once a thread has registered as listener on an event source it + * will be notified of all events broadcasted there. + * @note Multiple Event Listeners can specify the same bits to be ORed to + * different threads. + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[out] elp pointer to the @p event_listener_t structure + * @param[in] events the mask of events to be ORed to the thread when + * the event source is broadcasted + * + * @api + */ +#define chEvtRegisterMask(esp, elp, events) \ + chEvtRegisterMaskWithFlags(esp, elp, events, (eventflags_t)-1) + +/** + * @brief Registers an Event Listener on an Event Source. + * @note Multiple Event Listeners can use the same event identifier, the + * listener will share the callback function. + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[out] elp pointer to the @p event_listener_t structure + * @param[in] event numeric identifier assigned to the Event Listener. + * The value must range between zero and the size, in bit, + * of the @p eventmask_t type minus one. + * + * @api + */ +#define chEvtRegister(esp, elp, event) \ + chEvtRegisterMask(esp, elp, EVENT_MASK(event)) + +/** + * @brief Verifies if there is at least one @p event_listener_t registered. + * + * @param[in] esp pointer to the @p event_source_t structure + * @return The event source status. + * + * @iclass + */ +#define chEvtIsListeningI(esp) (bool)((esp) != (event_source_t *)(esp)->next) + +/** + * @brief Signals all the Event Listeners registered on the specified Event + * Source. + * + * @param[in] esp pointer to the @p event_source_t structure + * + * @api + */ +#define chEvtBroadcast(esp) chEvtBroadcastFlags(esp, (eventflags_t)0) + +/** + * @brief Signals all the Event Listeners registered on the specified Event + * Source. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] esp pointer to the @p event_source_t structure + * + * @iclass + */ +#define chEvtBroadcastI(esp) chEvtBroadcastFlagsI(esp, (eventflags_t)0) + +/** + * @brief Adds (OR) a set of events to the current thread, this is + * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal(). + * + * @param[in] events the events to be added + * @return The mask of currently pending events. + * + * @iclass + */ +#define chEvtAddEventsI(events) (nil.current->epmask |= events) + +/** + * @brief Returns the events mask. + * @details The pending events mask is returned but not altered in any way. + * + * @return The pending events mask. + * + * @api + */ +#define chEvtGetEventsX(void) (nil.current->epmask) + +/** + * @brief Waits for exactly one of the specified events. + * @details The function waits for one event among those specified in + * @p events to become pending then the event is cleared and returned. + * @note One and only one event is served in the function, the one with the + * lowest event id. The function is meant to be invoked into a loop + * in order to serve all the pending events.
+ * This means that Event Listeners with a lower event identifier have + * an higher priority. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS enables all the events + * @return The mask of the lowest event id served and cleared. + * @retval 0 if the operation has timed out. + * + * @api + */ +#define chEvtWaitOne(events) chEvtWaitOneTimeout(events, TIME_INFINITE) + +/** + * @brief Waits for any of the specified events. + * @details The function waits for any event among those specified in + * @p mask to become pending then the events are cleared and + * returned. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS enables all the events + * @return The mask of the served and cleared events. + * @retval 0 if the operation has timed out. + * + * @api + */ +#define chEvtWaitAny(events) chEvtWaitAnyTimeout(events, TIME_INFINITE) + +/** + * @brief Waits for all the specified events. + * @details The function waits for all the events specified in @p mask to + * become pending then the events are cleared and returned. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS enables all the events + * @return The mask of the served and cleared events. + * @retval 0 if the operation has timed out. + * + * @api + */ +#define chEvtWaitAll(events) chEvtWaitAllTimeout(events, TIME_INFINITE) + +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chEvtRegisterMaskWithFlags(event_source_t *esp, + event_listener_t *elp, + eventmask_t events, + eventflags_t wflags); + void chEvtUnregister(event_source_t *esp, event_listener_t *elp); + eventmask_t chEvtGetAndClearEventsI(eventmask_t events); + eventmask_t chEvtGetAndClearEvents(eventmask_t events); + eventmask_t chEvtAddEvents(eventmask_t events); + eventflags_t chEvtGetAndClearFlags(event_listener_t *elp); + eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp); + void chEvtSignal(thread_t *tp, eventmask_t events); + void chEvtSignalI(thread_t *tp, eventmask_t events); + void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags); + void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags); + void chEvtDispatch(const evhandler_t *handlers, eventmask_t events); + eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout); + eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout); + eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +#endif /* CHEVT_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/include/chmsg.h b/ChibiOS_20.3.2/os/nil/include/chmsg.h new file mode 100644 index 0000000..abe1de7 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/include/chmsg.h @@ -0,0 +1,123 @@ +/* + 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/chmsg.h + * @brief Nil RTOS synchronous messages header file. + * + * @addtogroup NIL_MESSAGES + * @{ + */ + +#ifndef CHMSG_H +#define CHMSG_H + +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Suspends the thread and waits for an incoming message. + * @post After receiving a message the function @p chMsgGet() must be + * called in order to retrieve the message and then @p chMsgRelease() + * must be invoked in order to acknowledge the reception and send + * the answer. + * @note If the message is a pointer then you can assume that the data + * pointed by the message is stable until you invoke @p chMsgRelease() + * because the sending thread is suspended until then. + * @note The reference counter of the sender thread is not increased, the + * returned pointer is a temporary reference. + * + * @return A pointer to the thread carrying the message. + * + * @sclass + */ +#define chMsgWaitS() chMsgWaitTimeoutS(TIME_INFINITE) + +/** + * @brief Returns the message carried by the specified thread. + * @pre This function must be invoked immediately after exiting a call + * to @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @return The message carried by the sender. + * + * @api + */ +#define chMsgGet(tp) ((tp)->sntmsg) + +/** + * @brief Releases the thread waiting on top of the messages queue. + * @pre Invoke this function only after a message has been received + * using @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @param[in] msg message to be returned to the sender + * + * @sclass + */ +#define chMsgReleaseS(tp, msg) do { \ + (void) chSchReadyI(tp, msg); \ + chSchRescheduleS(); \ + } while (false) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + msg_t chMsgSend(thread_t *tp, msg_t msg); + thread_t *chMsgWait(void); + thread_t *chMsgWaitTimeout(sysinterval_t timeout); + thread_t *chMsgWaitTimeoutS(sysinterval_t timeout); + void chMsgRelease(thread_t *tp, msg_t msg); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +#endif /* CHMSG_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/include/chsem.h b/ChibiOS_20.3.2/os/nil/include/chsem.h new file mode 100644 index 0000000..7caad00 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/include/chsem.h @@ -0,0 +1,180 @@ +/* + 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/chsem.h + * @brief Nil RTOS semaphores header file. + * + * @addtogroup NIL_SEMAPHORES + * @{ + */ + +#ifndef CHSEM_H +#define CHSEM_H + +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @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 reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * @note This function implicitly sends @p MSG_RESET as message. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * + * @api + */ +#define chSemReset(sp, n) chSemResetWithMessage(sp, n, MSG_RESET) + +/** + * @brief Performs a reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * @note This function implicitly sends @p MSG_RESET as message. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * + * @iclass + */ +#define chSemResetI(sp, n) chSemResetWithMessageI(sp, n, MSG_RESET) + +/** + * @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) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + 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 chSemResetWithMessage(semaphore_t *sp, cnt_t n, msg_t msg); + void chSemResetWithMessageI(semaphore_t *sp, cnt_t n, msg_t msg); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +#endif /* CHSEM_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/nil.mk b/ChibiOS_20.3.2/os/nil/nil.mk new file mode 100644 index 0000000..165b0e5 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/nil.mk @@ -0,0 +1,42 @@ +# List of all the ChibiOS/NIL kernel files, there is no need to remove the files +# from this list, you can disable parts of the kernel by editing chconf.h. +ifeq ($(USE_SMART_BUILD),yes) + +# Configuration files directory +ifeq ($(CHCONFDIR),) + ifeq ($(CONFDIR),) + CHCONFDIR = . + else + CHCONFDIR := $(CONFDIR) + endif +endif + +CHCONF := $(strip $(shell cat $(CHCONFDIR)/chconf.h | egrep -e "\#define")) + +KERNSRC := ${CHIBIOS}/os/nil/src/ch.c +ifneq ($(findstring CH_CFG_USE_EVENTS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/nil/src/chevt.c +endif +ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/nil/src/chmsg.c +endif +ifneq ($(findstring CH_CFG_USE_SEMAPHORES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/nil/src/chsem.c +endif + +else +KERNSRC := ${CHIBIOS}/os/nil/src/ch.c \ + ${CHIBIOS}/os/nil/src/chevt.c + ${CHIBIOS}/os/nil/src/chmsg.c \ + ${CHIBIOS}/os/nil/src/chsem.c +endif + +# Required include directories +KERNINC := ${CHIBIOS}/os/nil/include + +# Shared variables +ALLCSRC += $(KERNSRC) +ALLINC += $(KERNINC) + +# OS Library +include $(CHIBIOS)/os/oslib/oslib.mk diff --git a/ChibiOS_20.3.2/os/nil/src/ch.c b/ChibiOS_20.3.2/os/nil/src/ch.c new file mode 100644 index 0000000..35df8b6 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/src/ch.c @@ -0,0 +1,1080 @@ +/* + 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/src/ch.c + * @brief Nil RTOS main source file. + * + * @addtogroup NIL_KERNEL + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief System data structures. + */ +nil_system_t nil; + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Retrieves the highest priority thread in the specified state and + * associated to the specified object. + * + * @param[in] state thread state + * @param[in] p object pointer + * @return The pointer to the found thread. + * @retval NULL if the thread is not found. + * + * @notapi + */ +thread_t *nil_find_thread(tstate_t state, void *p) { + thread_t *tp = nil.threads; + + while (tp < &nil.threads[CH_CFG_MAX_THREADS]) { + /* Is this thread matching?*/ + if ((tp->state == state) && (tp->u1.p == p)) { + return tp; + } + tp++; + } + return NULL; +} + +/** + * @brief Puts in ready state all thread matching the specified status and + * associated object. + * + * @param[in] p object pointer + * @param[in] cnt number of threads to be readied as a negative number, + * non negative numbers are ignored + * @param[in] msg the wakeup message + * @return The number of readied threads. + * + * @notapi + */ +cnt_t nil_ready_all(void *p, cnt_t cnt, msg_t msg) { + thread_t *tp = nil.threads;; + + while (cnt < (cnt_t)0) { + + chDbgAssert(tp < &nil.threads[CH_CFG_MAX_THREADS], + "pointer out of range"); + + /* Is this thread waiting on this queue?*/ + if ((tp->state == NIL_STATE_WTQUEUE) && (tp->u1.p == p)) { + cnt++; + (void) chSchReadyI(tp, msg); + } + tp++; + } + + return cnt; +} + +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__) +/** + * @brief Guard code for @p chSysDisable(). + * + * @notapi + */ +void _dbg_check_disable(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#1"); + } +} + +/** + * @brief Guard code for @p chSysSuspend(). + * + * @notapi + */ +void _dbg_check_suspend(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#2"); + } +} + +/** + * @brief Guard code for @p chSysEnable(). + * + * @notapi + */ +void _dbg_check_enable(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#3"); + } +} + +/** + * @brief Guard code for @p chSysLock(). + * + * @notapi + */ +void _dbg_check_lock(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#4"); + } + _dbg_enter_lock(); +} + +/** + * @brief Guard code for @p chSysUnlock(). + * + * @notapi + */ +void _dbg_check_unlock(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#5"); + } + _dbg_leave_lock(); +} + +/** + * @brief Guard code for @p chSysLockFromIsr(). + * + * @notapi + */ +void _dbg_check_lock_from_isr(void) { + + if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#6"); + } + _dbg_enter_lock(); +} + +/** + * @brief Guard code for @p chSysUnlockFromIsr(). + * + * @notapi + */ +void _dbg_check_unlock_from_isr(void) { + + if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#7"); + } + _dbg_leave_lock(); +} + +/** + * @brief Guard code for @p CH_IRQ_PROLOGUE(). + * + * @notapi + */ +void _dbg_check_enter_isr(void) { + + port_lock_from_isr(); + if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#8"); + } + nil.isr_cnt++; + port_unlock_from_isr(); +} + +/** + * @brief Guard code for @p CH_IRQ_EPILOGUE(). + * + * @notapi + */ +void _dbg_check_leave_isr(void) { + + port_lock_from_isr(); + if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#9"); + } + nil.isr_cnt--; + port_unlock_from_isr(); +} + +/** + * @brief I-class functions context check. + * @details Verifies that the system is in an appropriate state for invoking + * an I-class API function. A panic is generated if the state is + * not compatible. + * + * @api + */ +void chDbgCheckClassI(void) { + + if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#10"); + } +} + +/** + * @brief S-class functions context check. + * @details Verifies that the system is in an appropriate state for invoking + * an S-class API function. A panic is generated if the state is + * not compatible. + * + * @api + */ +void chDbgCheckClassS(void) { + + if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#11"); + } +} +#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */ + +/** + * @brief Initializes the kernel. + * @details Initializes the kernel structures, the current instructions flow + * becomes the idle thread upon return. The idle thread must not + * invoke any kernel primitive able to change state to not runnable. + * @note This function assumes that the @p nil global variable has been + * zeroed by the runtime environment. If this is not the case then + * make sure to clear it before calling this function. + * + * @special + */ +void chSysInit(void) { + const thread_descriptor_t *tdp; + + /* Optional library modules.*/ + _oslib_init(); + + /* Architecture layer initialization.*/ + port_init(); + + /* System initialization hook.*/ + CH_CFG_SYSTEM_INIT_HOOK(); + + /* Making idle the current thread, this may change after rescheduling.*/ + nil.next = nil.current = &nil.threads[CH_CFG_MAX_THREADS]; + nil.current->state = NIL_STATE_READY; + +#if CH_DBG_ENABLE_STACK_CHECK == TRUE + /* The idle thread is a special case because its stack is set up by the + runtime environment.*/ + nil.threads[CH_CFG_MAX_THREADS].wabase = THD_IDLE_BASE; +#endif + + /* Interrupts partially enabled. It is equivalent to entering the + kernel critical zone.*/ + chSysSuspend(); +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + nil.lock_cnt = (cnt_t)1; +#endif + +#if CH_CFG_AUTOSTART_THREADS == TRUE + /* Iterates through the list of threads to be auto-started.*/ + tdp = nil_thd_configs; + do { + (void) chThdCreateI(tdp); + tdp++; + } while (tdp->funcp != NULL); +#endif + + /* Starting the dance.*/ + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Halts the system. + * @details This function is invoked by the operating system when an + * unrecoverable error is detected, for example because a programming + * error in the application code that triggers an assertion while + * in debug mode. + * @note Can be invoked from any system state. + * + * @param[in] reason pointer to an error string + * + * @special + */ +void chSysHalt(const char *reason) { + + port_disable(); + +#if NIL_DBG_ENABLED + nil.dbg_panic_msg = reason; +#else + (void)reason; +#endif + + /* Halt hook code, usually empty.*/ + CH_CFG_SYSTEM_HALT_HOOK(reason); + + /* Harmless infinite loop.*/ + while (true) { + } +} + +/** + * @brief Time management handler. + * @note This handler has to be invoked by a periodic ISR in order to + * reschedule the waiting threads. + * + * @iclass + */ +void chSysTimerHandlerI(void) { + + chDbgCheckClassI(); + +#if CH_CFG_ST_TIMEDELTA == 0 + thread_t *tp = &nil.threads[0]; + nil.systime++; + do { + /* Is the thread in a wait state with timeout?.*/ + if (tp->timeout > (sysinterval_t)0) { + + chDbgAssert(!NIL_THD_IS_READY(tp), "is ready"); + + /* Did the timer reach zero?*/ + if (--tp->timeout == (sysinterval_t)0) { + /* Timeout on queues/semaphores requires a special handling because + the counter must be incremented.*/ + /*lint -save -e9013 [15.7] There is no else because it is not needed.*/ +#if CH_CFG_USE_SEMAPHORES == TRUE + if (NIL_THD_IS_WTQUEUE(tp)) { + tp->u1.semp->cnt++; + } + else +#endif + if (NIL_THD_IS_SUSPENDED(tp)) { + *tp->u1.trp = NULL; + } + /*lint -restore*/ + (void) chSchReadyI(tp, MSG_TIMEOUT); + } + } + /* Lock released in order to give a preemption chance on those + architectures supporting IRQ preemption.*/ + chSysUnlockFromISR(); + tp++; + chSysLockFromISR(); + } while (tp < &nil.threads[CH_CFG_MAX_THREADS]); +#else + thread_t *tp = &nil.threads[0]; + sysinterval_t next = (sysinterval_t)0; + + chDbgAssert(nil.nexttime == port_timer_get_alarm(), "time mismatch"); + + do { + sysinterval_t timeout = tp->timeout; + + /* Is the thread in a wait state with timeout?.*/ + if (timeout > (sysinterval_t)0) { + + chDbgAssert(!NIL_THD_IS_READY(tp), "is ready"); + chDbgAssert(timeout >= chTimeDiffX(nil.lasttime, nil.nexttime), + "skipped one"); + + /* The volatile field is updated once, here.*/ + timeout -= chTimeDiffX(nil.lasttime, nil.nexttime); + tp->timeout = timeout; + + if (timeout == (sysinterval_t)0) { + /* Timeout on thread queues requires a special handling because the + counter must be incremented.*/ + if (NIL_THD_IS_WTQUEUE(tp)) { + tp->u1.tqp->cnt++; + } + else { + if (NIL_THD_IS_SUSPENDED(tp)) { + *tp->u1.trp = NULL; + } + } + (void) chSchReadyI(tp, MSG_TIMEOUT); + } + else { + if (timeout <= (sysinterval_t)(next - (sysinterval_t)1)) { + next = timeout; + } + } + } + + /* Lock released in order to give a preemption chance on those + architectures supporting IRQ preemption.*/ + chSysUnlockFromISR(); + tp++; + chSysLockFromISR(); + } while (tp < &nil.threads[CH_CFG_MAX_THREADS]); + + nil.lasttime = nil.nexttime; + if (next > (sysinterval_t)0) { + nil.nexttime = chTimeAddX(nil.nexttime, next); + port_timer_set_alarm(nil.nexttime); + } + else { + /* No tick event needed.*/ + port_timer_stop_alarm(); + } +#endif +} + +/** + * @brief Unconditionally enters the kernel lock state. + * @note Can be called without previous knowledge of the current lock state. + * The final state is "s-locked". + * + * @special + */ +void chSysUnconditionalLock(void) { + + if (port_irq_enabled(port_get_irq_status())) { + chSysLock(); + } +} + +/** + * @brief Unconditionally leaves the kernel lock state. + * @note Can be called without previous knowledge of the current lock state. + * The final state is "normal". + * + * @special + */ +void chSysUnconditionalUnlock(void) { + + if (!port_irq_enabled(port_get_irq_status())) { + chSysUnlock(); + } +} + +/** + * @brief Returns the execution status and enters a critical zone. + * @details This functions enters into a critical zone and can be called + * from any context. Because its flexibility it is less efficient + * than @p chSysLock() which is preferable when the calling context + * is known. + * @post The system is in a critical zone. + * + * @return The previous system status, the encoding of this + * status word is architecture-dependent and opaque. + * + * @xclass + */ +syssts_t chSysGetStatusAndLockX(void) { + + syssts_t sts = port_get_irq_status(); + if (port_irq_enabled(sts)) { + if (port_is_isr_context()) { + chSysLockFromISR(); + } + else { + chSysLock(); + } + } + return sts; +} + +/** + * @brief Restores the specified execution status and leaves a critical zone. + * @note A call to @p chSchRescheduleS() is automatically performed + * if exiting the critical zone and if not in ISR context. + * + * @param[in] sts the system status to be restored. + * + * @xclass + */ +void chSysRestoreStatusX(syssts_t sts) { + + if (port_irq_enabled(sts)) { + if (port_is_isr_context()) { + chSysUnlockFromISR(); + } + else { + chSchRescheduleS(); + chSysUnlock(); + } + } +} + +#if (PORT_SUPPORTS_RT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Realtime window test. + * @details This function verifies if the current realtime counter value + * lies within the specified range or not. The test takes care + * of the realtime counter wrapping to zero on overflow. + * @note When start==end then the function returns always false because a + * null time range is specified. + * @note This function is only available if the port layer supports the + * option @p PORT_SUPPORTS_RT. + * + * @param[in] cnt the counter value to be tested + * @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 + */ +bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end) { + + return (bool)(((rtcnt_t)cnt - (rtcnt_t)start) < + ((rtcnt_t)end - (rtcnt_t)start)); +} + +/** + * @brief Polled delay. + * @note The real delay is always few cycles in excess of the specified + * value. + * @note This function is only available if the port layer supports the + * option @p PORT_SUPPORTS_RT. + * + * @param[in] cycles number of cycles + * + * @xclass + */ +void chSysPolledDelayX(rtcnt_t cycles) { + rtcnt_t start = chSysGetRealtimeCounterX(); + rtcnt_t end = start + cycles; + + while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) { + } +} +#endif /* PORT_SUPPORTS_RT == TRUE */ + +/** + * @brief Makes the specified thread ready for execution. + * + * @param[in] tp pointer to the @p thread_t object + * @param[in] msg the wakeup message + * + * @return The same reference passed as parameter. + */ +thread_t *chSchReadyI(thread_t *tp, msg_t msg) { + + chDbgCheckClassI(); + chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_MAX_THREADS])); + chDbgAssert(!NIL_THD_IS_READY(tp), "already ready"); + chDbgAssert(nil.next <= nil.current, "priority ordering"); + + tp->u1.msg = msg; + tp->state = NIL_STATE_READY; + tp->timeout = (sysinterval_t)0; + if (tp < nil.next) { + nil.next = tp; + } + return tp; +} + +/** + * @brief Evaluates if preemption is required. + * @details The decision is taken by comparing the relative priorities and + * depending on the state of the round robin timeout counter. + * @note Not a user function, it is meant to be invoked by the scheduler + * itself or from within the port layer. + * + * @retval true if there is a thread that must go in running state + * immediately. + * @retval false if preemption is not required. + * + * @special + */ +bool chSchIsPreemptionRequired(void) { + + return chSchIsRescRequiredI(); +} + +/** + * @brief Switches to the first thread on the runnable queue. + * @note Not a user function, it is meant to be invoked by the scheduler + * itself or from within the port layer. + * + * @special + */ +void chSchDoReschedule(void) { + thread_t *otp = nil.current; + + nil.current = nil.next; + if (otp == &nil.threads[CH_CFG_MAX_THREADS]) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + port_switch(nil.next, otp); +} + +/** + * @brief Reschedules if needed. + * + * @sclass + */ +void chSchRescheduleS(void) { + + chDbgCheckClassS(); + + if (chSchIsRescRequiredI()) { + chSchDoReschedule(); + } +} + +/** + * @brief Puts the current thread to sleep into the specified state with + * timeout specification. + * @details The thread goes into a sleeping state, if it is not awakened + * explicitly within the specified system time then it is forcibly + * awakened with a @p MSG_TIMEOUT low level message. + * + * @param[in] newstate the new thread state or a semaphore pointer + * @param[in] timeout the number of ticks before the operation timeouts. + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The wakeup message. + * @retval MSG_TIMEOUT if a timeout occurred. + * + * @sclass + */ +msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) { + thread_t *ntp, *otp = nil.current; + + chDbgCheckClassS(); + + chDbgAssert(otp != &nil.threads[CH_CFG_MAX_THREADS], + "idle cannot sleep"); + + /* Storing the wait object for the current thread.*/ + otp->state = newstate; + +#if CH_CFG_ST_TIMEDELTA > 0 + if (timeout != TIME_INFINITE) { + systime_t abstime; + + /* TIMEDELTA makes sure to have enough time to reprogram the timer + before the free-running timer counter reaches the selected timeout.*/ + if (timeout < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { + timeout = (sysinterval_t)CH_CFG_ST_TIMEDELTA; + } + + /* Absolute time of the timeout event.*/ + abstime = chTimeAddX(chVTGetSystemTimeX(), timeout); + + if (nil.lasttime == nil.nexttime) { + /* Special case, first thread asking for a timeout.*/ + port_timer_start_alarm(abstime); + nil.nexttime = abstime; + } + else { + /* Special case, there are already other threads with a timeout + activated, evaluating the order.*/ + if (chTimeIsInRangeX(abstime, nil.lasttime, nil.nexttime)) { + port_timer_set_alarm(abstime); + nil.nexttime = abstime; + } + } + + /* Timeout settings.*/ + otp->timeout = abstime - nil.lasttime; + } +#else + + /* Timeout settings.*/ + otp->timeout = timeout; +#endif + + /* Scanning the whole threads array.*/ + ntp = nil.threads; + while (true) { + /* Is this thread ready to execute?*/ + if (NIL_THD_IS_READY(ntp)) { + nil.current = nil.next = ntp; + if (ntp == &nil.threads[CH_CFG_MAX_THREADS]) { + CH_CFG_IDLE_ENTER_HOOK(); + } + port_switch(ntp, otp); + return nil.current->u1.msg; + } + + /* Points to the next thread in lowering priority order.*/ + ntp++; + chDbgAssert(ntp <= &nil.threads[CH_CFG_MAX_THREADS], + "pointer out of range"); + } +} + +/** + * @brief Checks if the specified time is within the specified time range. + * @note When start==end then the function returns always false because the + * time window has zero size. + * + * @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 + */ +bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end) { + + return (bool)((systime_t)((systime_t)(time) - (systime_t)(start)) < + (systime_t)((systime_t)(end) - (systime_t)(start))); +} + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized and make ready to execute. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * + * @param[out] tdp pointer to the thread descriptor structure + * @return The pointer to the @p thread_t structure allocated for + * the thread. + * + * @iclass + */ +thread_t *chThdCreateI(const thread_descriptor_t *tdp) { + thread_t *tp; + + chDbgCheck((tdp->prio < (tprio_t)CH_CFG_MAX_THREADS) && + (tdp->wbase != NULL) && + MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) && + (tdp->wend > tdp->wbase) && + MEM_IS_ALIGNED(tdp->wbase, PORT_STACK_ALIGN) && + (tdp->funcp != NULL)); + + chDbgCheckClassI(); + + /* Pointer to the thread slot to be used.*/ + tp = &nil.threads[tdp->prio]; + chDbgAssert(NIL_THD_IS_WTSTART(tp) || NIL_THD_IS_FINAL(tp), + "priority slot taken"); + +#if CH_CFG_USE_EVENTS == TRUE + tp->epmask = (eventmask_t)0; +#endif +#if CH_DBG_ENABLE_STACK_CHECK == TRUE + tp->wabase = (stkalign_t *)tdp->wbase; +#endif + + /* Port dependent thread initialization.*/ + PORT_SETUP_CONTEXT(tp, tdp->wbase, tdp->wend, tdp->funcp, tdp->arg); + + /* Initialization hook.*/ + CH_CFG_THREAD_EXT_INIT_HOOK(tp); + + /* Readying up thread.*/ + return chSchReadyI(tp, MSG_OK); +} + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized and make ready to execute. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * + * @param[out] tdp pointer to the thread descriptor structure + * @return The pointer to the @p thread_t structure allocated for + * the thread. + * + * @api + */ +thread_t *chThdCreate(const thread_descriptor_t *tdp) { + thread_t *tp; + + chSysLock(); + tp = chThdCreateI(tdp); + chSchRescheduleS(); + chSysUnlock(); + + return tp; +} + +/** + * @brief Terminates the current thread. + * @details The thread goes in the @p CH_STATE_FINAL state holding the + * specified exit status code, other threads can retrieve the + * exit status code by invoking the function @p chThdWait(). + * @post Exiting a non-static thread that does not have references + * (detached) causes the thread to remain in the registry. + * It can only be removed by performing a registry scan operation. + * @post Eventual code after this function will never be executed, + * this function never returns. The compiler has no way to + * know this so do not assume that the compiler would remove + * the dead code. + * + * @param[in] msg thread exit code + * + * @api + */ +void chThdExit(msg_t msg) { + + chSysLock(); + + /* Exit handler hook.*/ + CH_CFG_THREAD_EXIT_HOOK(tp); + +#if CH_CFG_USE_WAITEXIT == TRUE + { + /* Waking up any waiting thread.*/ + thread_t *tp = nil.threads; + while (tp < &nil.threads[CH_CFG_MAX_THREADS]) { + /* Is this thread waiting for current thread termination?*/ + if ((tp->state == NIL_STATE_WTEXIT) && (tp->u1.tp == nil.current)) { + (void) chSchReadyI(tp, msg); + } + tp++; + } + } +#endif + + /* Going into final state with exit message stored.*/ + nil.current->u1.msg = msg; + (void) chSchGoSleepTimeoutS(NIL_STATE_FINAL, TIME_INFINITE); + + /* The thread never returns here.*/ + chDbgAssert(false, "zombies apocalypse"); +} + +/** + * @brief Blocks the execution of the invoking thread until the specified + * thread terminates then the exit code is returned. + * + * @param[in] tp pointer to the thread + * @return The exit code from the terminated thread. + * + * @api + */ +msg_t chThdWait(thread_t *tp) { + msg_t msg; + + chSysLock(); + if (NIL_THD_IS_FINAL(tp)) { + msg = tp->u1.msg; + } + else { + nil.current->u1.tp = tp; + msg = chSchGoSleepTimeoutS(NIL_STATE_WTEXIT, TIME_INFINITE); + } + chSysUnlock(); + + return msg; +} + +/** + * @brief Sends the current thread sleeping and sets a reference variable. + * @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] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The wake up message. + * + * @sclass + */ +msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout) { + + chDbgAssert(*trp == NULL, "not NULL"); + + if (TIME_IMMEDIATE == timeout) { + return MSG_TIMEOUT; + } + + *trp = nil.current; + nil.current->u1.trp = trp; + return chSchGoSleepTimeoutS(NIL_STATE_SUSPENDED, timeout); +} + +/** + * @brief Wakes up a thread waiting on a thread reference object. + * @note This function must not reschedule because it can be called from + * ISR context. + * + * @param[in] trp a pointer to a thread reference object + * @param[in] msg the message code + * + * @iclass + */ +void chThdResumeI(thread_reference_t *trp, msg_t msg) { + + if (*trp != NULL) { + thread_reference_t tr = *trp; + + chDbgAssert(NIL_THD_IS_SUSPENDED(tr), "not suspended"); + + *trp = NULL; + (void) chSchReadyI(tr, msg); + } +} + +/** + * @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 + * + * @api + */ +void chThdResume(thread_reference_t *trp, msg_t msg) { + + chSysLock(); + chThdResumeS(trp, msg); + chSysUnlock(); +} + +/** + * @brief Suspends the invoking thread for the specified time. + * + * @param[in] timeout the delay in system ticks + * + * @api + */ +void chThdSleep(sysinterval_t timeout) { + + chSysLock(); + chThdSleepS(timeout); + chSysUnlock(); +} + +/** + * @brief Suspends the invoking thread until the system time arrives to the + * specified value. + * + * @param[in] abstime absolute system time + * + * @api + */ +void chThdSleepUntil(systime_t abstime) { + + chSysLock(); + chThdSleepUntilS(abstime); + chSysUnlock(); +} + +/** + * @brief Enqueues the caller thread on a threads queue object. + * @details The caller thread is enqueued and put to sleep until it is + * dequeued or the specified timeouts expires. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] timeout the timeout in system ticks, the special values are + * handled as follow: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The message from @p osalQueueWakeupOneI() or + * @p osalQueueWakeupAllI() functions. + * @retval MSG_TIMEOUT if the thread has not been dequeued within the + * specified timeout or if the function has been + * invoked with @p TIME_IMMEDIATE as timeout + * specification. + * + * @sclass + */ +msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout) { + + chDbgCheckClassS(); + chDbgCheck(tqp != NULL); + + chDbgAssert(tqp->cnt <= (cnt_t)0, "invalid counter"); + + if (TIME_IMMEDIATE == timeout) { + return MSG_TIMEOUT; + } + + tqp->cnt--; + nil.current->u1.tqp = tqp; + return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); +} + +/** + * @brief Dequeues and wakes up one thread from the threads queue object. + * @details Dequeues one thread from the queue without checking if the queue + * is empty. + * @pre The queue must contain at least an object. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] msg the message code + * + * @iclass + */ +void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) { + thread_t *tp; + + chDbgAssert(tqp->cnt < (cnt_t)0, "empty queue"); + + tqp->cnt++; + tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)tqp); + + chDbgAssert(tp != NULL, "thread not found"); + + (void) chSchReadyI(tp, msg); +} + +/** + * @brief Dequeues and wakes up one thread from the threads queue object, + * if any. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] msg the message code + * + * @iclass + */ +void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg) { + + chDbgCheckClassI(); + chDbgCheck(tqp != NULL); + + if (tqp->cnt < (cnt_t)0) { + chThdDoDequeueNextI(tqp, msg); + } +} + +/** + * @brief Dequeues and wakes up all threads from the threads queue object. + * + * @param[in] tqp pointer to the threads queue object + * @param[in] msg the message code + * + * @iclass + */ +void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg) { + + chDbgCheckClassI(); + chDbgCheck(tqp != NULL); + + tqp->cnt = nil_ready_all((void *)tqp, tqp->cnt, msg); +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/src/chevt.c b/ChibiOS_20.3.2/os/nil/src/chevt.c new file mode 100644 index 0000000..ed33af4 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/src/chevt.c @@ -0,0 +1,478 @@ +/* + 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/src/chevt.c + * @brief Nil RTOS events source file. + * + * @addtogroup NIL_EVENTS + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Registers an Event Listener on an Event Source. + * @details Once a thread has registered as listener on an event source it + * will be notified of all events broadcasted there. + * @note Multiple Event Listeners can specify the same bits to be ORed to + * different threads. + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[in] elp pointer to the @p event_listener_t structure + * @param[in] events events to be ORed to the thread when + * the event source is broadcasted + * @param[in] wflags mask of flags the listening thread is interested in + * + * @api + */ +void chEvtRegisterMaskWithFlags(event_source_t *esp, + event_listener_t *elp, + eventmask_t events, + eventflags_t wflags) { + + chDbgCheck((esp != NULL) && (elp != NULL)); + + chSysLock(); + elp->next = esp->next; + esp->next = elp; + elp->listener = chThdGetSelfX(); + elp->events = events; + elp->flags = (eventflags_t)0; + elp->wflags = wflags; + chSysUnlock(); +} + +/** + * @brief Unregisters an Event Listener from its Event Source. + * @note If the event listener is not registered on the specified event + * source then the function does nothing. + * @note For optimal performance it is better to perform the unregister + * operations in inverse order of the register operations (elements + * are found on top of the list). + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[in] elp pointer to the @p event_listener_t structure + * + * @api + */ +void chEvtUnregister(event_source_t *esp, event_listener_t *elp) { + event_listener_t *p; + + chDbgCheck((esp != NULL) && (elp != NULL)); + + /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ + p = (event_listener_t *)esp; + /*lint -restore*/ + chSysLock(); + /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ + while (p->next != (event_listener_t *)esp) { + /*lint -restore*/ + if (p->next == elp) { + p->next = elp->next; + break; + } + p = p->next; + } + chSysUnlock(); +} + +/** + * @brief Clears the pending events specified in the events mask. + * + * @param[in] events the events to be cleared + * @return The mask of pending events that were cleared. + * + * @iclass + */ +eventmask_t chEvtGetAndClearEventsI(eventmask_t events) { + eventmask_t m; + + m = chThdGetSelfX()->epmask & events; + chThdGetSelfX()->epmask &= ~events; + + return m; +} + +/** + * @brief Clears the pending events specified in the events mask. + * + * @param[in] events the events to be cleared + * @return The mask of pending events that were cleared. + * + * @api + */ +eventmask_t chEvtGetAndClearEvents(eventmask_t events) { + eventmask_t m; + + chSysLock(); + m = chEvtGetAndClearEventsI(events); + chSysUnlock(); + + return m; +} + +/** + * @brief Adds (OR) a set of events to the current thread, this is + * @b much faster than using @p chEvtBroadcast() or @p chEvtSignal(). + * + * @param[in] events the events to be added + * @return The mask of currently pending events. + * + * @api + */ +eventmask_t chEvtAddEvents(eventmask_t events) { + eventmask_t newevt; + + chSysLock(); + newevt = chEvtAddEventsI(events); + chSysUnlock(); + + return newevt; +} + +/** + * @brief Signals all the Event Listeners registered on the specified Event + * Source. + * @details This function variants ORs the specified event flags to all the + * threads registered on the @p event_source_t in addition to the + * event flags specified by the threads themselves in the + * @p event_listener_t objects. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[in] flags the flags set to be added to the listener flags mask + * + * @iclass + */ +void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags) { + event_listener_t *elp; + + chDbgCheckClassI(); + chDbgCheck(esp != NULL); + + elp = esp->next; + /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ + while (elp != (event_listener_t *)esp) { + /*lint -restore*/ + elp->flags |= flags; + /* When flags == 0 the thread will always be signaled because the + source does not emit any flag.*/ + if ((flags == (eventflags_t)0) || + ((flags & elp->wflags) != (eventflags_t)0)) { + chEvtSignalI(elp->listener, elp->events); + } + elp = elp->next; + } +} + +/** + * @brief Returns the flags associated to an @p event_listener_t. + * @details The flags are returned and the @p event_listener_t flags mask is + * cleared. + * + * @param[in] elp pointer to the @p event_listener_t structure + * @return The flags added to the listener by the associated + * event source. + * + * @api + */ +eventflags_t chEvtGetAndClearFlags(event_listener_t *elp) { + eventflags_t flags; + + chSysLock(); + flags = elp->flags; + elp->flags = (eventflags_t)0; + chSysUnlock(); + + return flags & elp->wflags; +} + +/** + * @brief Adds a set of event flags directly to the specified @p thread_t. + * + * @param[in] tp the thread to be signaled + * @param[in] events the event flags set to be ORed + * + * @api + */ +void chEvtSignal(thread_t *tp, eventmask_t events) { + + chSysLock(); + chEvtSignalI(tp, events); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Adds a set of event flags directly to the specified @p thread_t. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] tp the thread to be signaled + * @param[in] events the event flags set to be ORed + * + * @iclass + */ +void chEvtSignalI(thread_t *tp, eventmask_t events) { + + chDbgCheckClassI(); + chDbgCheck(tp != NULL); + + tp->epmask |= events; + if ((NIL_THD_IS_WTOREVT(tp) && + ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) || + (NIL_THD_IS_WTANDEVT(tp) && + ((tp->epmask & tp->u1.ewmask) == tp->u1.ewmask))) { + (void) chSchReadyI(tp, MSG_OK); + } +} + +/** + * @brief Signals all the Event Listeners registered on the specified Event + * Source. + * @details This function variants ORs the specified event flags to all the + * threads registered on the @p event_source_t in addition to the + * event flags specified by the threads themselves in the + * @p event_listener_t objects. + * + * @param[in] esp pointer to the @p event_source_t structure + * @param[in] flags the flags set to be added to the listener flags mask + * + * @api + */ +void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags) { + + chSysLock(); + chEvtBroadcastFlagsI(esp, flags); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Returns the unmasked flags associated to an @p event_listener_t. + * @details The flags are returned and the @p event_listener_t flags mask is + * cleared. + * + * @param[in] elp pointer to the @p event_listener_t structure + * @return The flags added to the listener by the associated + * event source. + * + * @iclass + */ +eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) { + eventflags_t flags; + + flags = elp->flags; + elp->flags = (eventflags_t)0; + + return flags & elp->wflags; +} + +/** + * @brief Invokes the event handlers associated to an event flags mask. + * + * @param[in] events mask of events to be dispatched + * @param[in] handlers an array of @p evhandler_t. The array must have size + * equal to the number of bits in eventmask_t. + * + * @api + */ +void chEvtDispatch(const evhandler_t *handlers, eventmask_t events) { + eventid_t eid; + + chDbgCheck(handlers != NULL); + + eid = (eventid_t)0; + while (events != (eventmask_t)0) { + if ((events & EVENT_MASK(eid)) != (eventmask_t)0) { + chDbgAssert(handlers[eid] != NULL, "null handler"); + events &= ~EVENT_MASK(eid); + handlers[eid](eid); + } + eid++; + } +} + +/** + * @brief Waits for exactly one of the specified events. + * @details The function waits for one event among those specified in + * @p events to become pending then the event is cleared and returned. + * @note One and only one event is served in the function, the one with the + * lowest event id. The function is meant to be invoked into a loop + * in order to serve all the pending events.
+ * This means that Event Listeners with a lower event identifier have + * an higher priority. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS enables all the events + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The mask of the lowest event id served and cleared. + * @retval 0 if the operation has timed out. + * + * @api + */ +eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout) { + thread_t *ctp = nil.current; + eventmask_t m; + + chSysLock(); + m = ctp->epmask & events; + if (m == (eventmask_t)0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + + return (eventmask_t)0; + } + ctp->u1.ewmask = events; + if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + + return (eventmask_t)0; + } + m = ctp->epmask & events; + } + m ^= m & (m - (eventmask_t)1); + ctp->epmask &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for any of the specified events. + * @details The function waits for any event among those specified in + * @p mask to become pending then the events are cleared and + * returned. + * + * @param[in] mask mask of the event flags that the function should wait + * for, @p ALL_EVENTS enables all the events + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The mask of the served and cleared events. + * @retval 0 if the operation has timed out. + * + * @api + */ +eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, sysinterval_t timeout) { + thread_t *ctp = nil.current; + eventmask_t m; + + chSysLock(); + if ((m = (ctp->epmask & mask)) == (eventmask_t)0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + + return (eventmask_t)0; + } + ctp->u1.ewmask = mask; + if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + + return (eventmask_t)0; + } + m = ctp->epmask & mask; + } + ctp->epmask &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for all the specified events. + * @details The function waits for all the events specified in @p mask to + * become pending then the events are cleared and returned. + * + * @param[in] mask mask of the event flags that the function should wait + * for, @p ALL_EVENTS enables all the events + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The mask of the served and cleared events. + * @retval 0 if the operation has timed out. + * + * @api + */ +eventmask_t chEvtWaitAllTimeout(eventmask_t mask, sysinterval_t timeout) { + thread_t *ctp = nil.current; + + chSysLock(); + if ((ctp->epmask & mask) != mask) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + + return (eventmask_t)0; + } + ctp->u1.ewmask = mask; + if (chSchGoSleepTimeoutS(NIL_STATE_WTANDEVT, timeout) < MSG_OK) { + chSysUnlock(); + + return (eventmask_t)0; + } + } + ctp->epmask &= ~mask; + chSysUnlock(); + + return mask; +} + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/src/chmsg.c b/ChibiOS_20.3.2/os/nil/src/chmsg.c new file mode 100644 index 0000000..ccefcc5 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/src/chmsg.c @@ -0,0 +1,201 @@ +/* + 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/src/chmsg.c + * @brief Nil RTOS synchronous messages source file. + * + * @addtogroup NIL_MESSAGES + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Sends a message to the specified thread. + * @details The sender is stopped until the receiver executes a + * @p chMsgRelease()after receiving the message. + * + * @param[in] tp the pointer to the thread + * @param[in] msg the message + * @return The answer message from @p chMsgRelease(). + * + * @api + */ +msg_t chMsgSend(thread_t *tp, msg_t msg) { + thread_t *ctp = nil.current; + + chDbgCheck(tp != NULL); + + chSysLock(); + ctp->sntmsg = msg; + ctp->u1.tp = tp; + if (NIL_THD_IS_WTMSG(tp)) { + (void) chSchReadyI(tp, (msg_t)ctp); + } + msg = chSchGoSleepTimeoutS(NIL_STATE_SNDMSGQ, TIME_INFINITE); + chSysUnlock(); + + return msg; +} + +/** + * @brief Suspends the thread and waits for an incoming message. + * @post After receiving a message the function @p chMsgGet() must be + * called in order to retrieve the message and then @p chMsgRelease() + * must be invoked in order to acknowledge the reception and send + * the answer. + * @note If the message is a pointer then you can assume that the data + * pointed by the message is stable until you invoke @p chMsgRelease() + * because the sending thread is suspended until then. + * @note The reference counter of the sender thread is not increased, the + * returned pointer is a temporary reference. + * + * @return A pointer to the thread carrying the message. + * + * @api + */ +thread_t *chMsgWait(void) { + thread_t *tp; + + chSysLock(); + tp = chMsgWaitS(); + chSysUnlock(); + + return tp; +} + +/** + * @brief Suspends the thread and waits for an incoming message or a + * timeout to occur. + * @post After receiving a message the function @p chMsgGet() must be + * called in order to retrieve the message and then @p chMsgRelease() + * must be invoked in order to acknowledge the reception and send + * the answer. + * @note If the message is a pointer then you can assume that the data + * pointed by the message is stable until you invoke @p chMsgRelease() + * because the sending thread is suspended until then. + * @note The reference counter of the sender thread is not increased, the + * returned pointer is a temporary reference. + * + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return A pointer to the thread carrying the message. + * @retval NULL if a timeout occurred. + * + * @api + */ +thread_t *chMsgWaitTimeout(sysinterval_t timeout) { + thread_t *tp; + + chSysLock(); + tp = chMsgWaitTimeoutS(timeout); + chSysUnlock(); + + return tp; +} + +/** + * @brief Suspends the thread and waits for an incoming message or a + * timeout to occur. + * @post After receiving a message the function @p chMsgGet() must be + * called in order to retrieve the message and then @p chMsgRelease() + * must be invoked in order to acknowledge the reception and send + * the answer. + * @note If the message is a pointer then you can assume that the data + * pointed by the message is stable until you invoke @p chMsgRelease() + * because the sending thread is suspended until then. + * @note The reference counter of the sender thread is not increased, the + * returned pointer is a temporary reference. + * + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return A pointer to the thread carrying the message. + * @retval NULL if a timeout occurred. + * + * @sclass + */ +thread_t *chMsgWaitTimeoutS(sysinterval_t timeout) { + thread_t *tp; + + chDbgCheckClassS(); + + tp = nil_find_thread(NIL_STATE_SNDMSGQ, nil.current); + if (tp == NULL) { + msg_t msg = chSchGoSleepTimeoutS(NIL_STATE_WTMSG, timeout); + if (msg != MSG_TIMEOUT) { + return (thread_t *)msg; + } + } + + return tp; +} + +/** + * @brief Releases a sender thread specifying a response message. + * @pre Invoke this function only after a message has been received + * using @p chMsgWait(). + * + * @param[in] tp pointer to the thread + * @param[in] msg message to be returned to the sender + * + * @api + */ +void chMsgRelease(thread_t *tp, msg_t msg) { + + chSysLock(); + chDbgAssert(tp->state == NIL_STATE_SNDMSGQ, "invalid state"); + chMsgReleaseS(tp, msg); + chSysUnlock(); +} + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/src/chsem.c b/ChibiOS_20.3.2/os/nil/src/chsem.c new file mode 100644 index 0000000..c97eb3a --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/src/chsem.c @@ -0,0 +1,224 @@ +/* + 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/src/chsem.c + * @brief Nil RTOS semaphores source file. + * + * @addtogroup NIL_SEMAPHORES + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Performs a wait operation on a semaphore with timeout specification. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return A message specifying how the invoking thread has been + * released from the semaphore. + * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). + * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within + * the specified timeout. + * + * @api + */ +msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout) { + msg_t msg; + + chSysLock(); + msg = chSemWaitTimeoutS(sp, timeout); + chSysUnlock(); + + return msg; +} + +/** + * @brief Performs a wait operation on a semaphore with timeout specification. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return A message specifying how the invoking thread has been + * released from the semaphore. + * @retval NIL_MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval NIL_MSG_RST if the semaphore has been reset using @p chSemReset(). + * @retval NIL_MSG_TMO if the semaphore has not been signaled or reset within + * the specified timeout. + * + * @sclass + */ +msg_t chSemWaitTimeoutS(semaphore_t *sp, sysinterval_t timeout) { + + chDbgCheckClassS(); + chDbgCheck(sp != NULL); + + /* Note, the semaphore counter is a volatile variable so accesses are + manually optimized.*/ + cnt_t cnt = sp->cnt; + if (cnt <= (cnt_t)0) { + if (TIME_IMMEDIATE == timeout) { + + return MSG_TIMEOUT; + } + sp->cnt = cnt - (cnt_t)1; + nil.current->u1.semp = sp; + + return chSchGoSleepTimeoutS(NIL_STATE_WTQUEUE, timeout); + } + sp->cnt = cnt - (cnt_t)1; + + return MSG_OK; +} + +/** + * @brief Performs a signal operation on a semaphore. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @api + */ +void chSemSignal(semaphore_t *sp) { + + chSysLock(); + chSemSignalI(sp); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Performs a signal operation on a semaphore. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] sp pointer to a @p semaphore_t structure + * + * @iclass + */ +void chSemSignalI(semaphore_t *sp) { + + chDbgCheckClassI(); + chDbgCheck(sp != NULL); + + if (++sp->cnt <= (cnt_t)0) { + thread_t *tp = nil_find_thread(NIL_STATE_WTQUEUE, (void *)sp); + + chDbgAssert(tp != NULL, "thread not found"); + + (void) chSchReadyI(tp, MSG_OK); + } +} + +/** + * @brief Performs a reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * @param[in] msg message to be sent + * + * @api + */ +void chSemResetWithMessage(semaphore_t *sp, cnt_t n, msg_t msg) { + + chSysLock(); + chSemResetWithMessageI(sp, n, msg); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Performs a reset operation on the semaphore. + * @post After invoking this function all the threads waiting on the + * semaphore, if any, are released and the semaphore counter is set + * to the specified, non negative, value. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @param[in] n the new value of the semaphore counter. The value must + * be non-negative. + * @param[in] msg message to be sent + * + * @iclass + */ +void chSemResetWithMessageI(semaphore_t *sp, cnt_t n, msg_t msg) { + cnt_t cnt; + + chDbgCheckClassI(); + chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); + + cnt = sp->cnt; + sp->cnt = n; + + /* Does nothing for cnt >= 0, calling anyway.*/ + (void) nil_ready_all((void *)sp, cnt, msg); +} + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/nil/templates/chconf.h b/ChibiOS_20.3.2/os/nil/templates/chconf.h new file mode 100644 index 0000000..3f0c953 --- /dev/null +++ b/ChibiOS_20.3.2/os/nil/templates/chconf.h @@ -0,0 +1,479 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file nil/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup NIL_CONFIG + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_NIL_CONF_ +#define _CHIBIOS_NIL_CONF_VER_4_0_ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Maximum number of user threads in the application. + * @note This number is not inclusive of the idle thread which is + * implicitly handled. + * @note Set this value to be exactly equal to the number of threads you + * will use or you would be wasting RAM and cycles. + * @note This values also defines the number of available priorities + * (0..CH_CFG_MAX_THREADS-1). + */ +#if !defined(CH_CFG_MAX_THREADS) +#define CH_CFG_MAX_THREADS 4 +#endif + +/** + * @brief Auto starts threads when @p chSysInit() is invoked. + */ +#if !defined(CH_CFG_AUTOSTART_THREADS) +#define CH_CFG_AUTOSTART_THREADS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name System timer settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#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) +#define CH_CFG_ST_FREQUENCY 1000 +#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) +#define CH_CFG_ST_TIMEDELTA 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#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) +#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) +#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) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @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) +#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) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#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) +#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) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @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) +#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) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note Feature not currently implemented. + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK TRUE +#endif + +/** + * @brief Debug option, parameters checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS TRUE +#endif + +/** + * @brief System assertions. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS TRUE +#endif + +/** + * @brief Stack check. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System initialization hook. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() { \ +} + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXT_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + */ +#define CH_CFG_THREAD_EXT_INIT_HOOK(tr) { \ + /* Add custom threads initialization code here.*/ \ +} + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) {} + +/** + * @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. + */ +#define CH_CFG_IDLE_ENTER_HOOK() { \ +} + +/** + * @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. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() { \ +} + +/** + * @brief System halt hook. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \ +} + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in nilcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ -- cgit v1.2.3