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/rt/dox/rt.dox | 152 +++++ ChibiOS_20.3.2/os/rt/include/ch.h | 135 ++++ ChibiOS_20.3.2/os/rt/include/chalign.h | 120 ++++ ChibiOS_20.3.2/os/rt/include/chchecks.h | 263 ++++++++ ChibiOS_20.3.2/os/rt/include/chcond.h | 116 ++++ ChibiOS_20.3.2/os/rt/include/chdebug.h | 169 +++++ ChibiOS_20.3.2/os/rt/include/chdynamic.h | 99 +++ ChibiOS_20.3.2/os/rt/include/chevents.h | 291 +++++++++ ChibiOS_20.3.2/os/rt/include/chmsg.h | 212 ++++++ ChibiOS_20.3.2/os/rt/include/chmtx.h | 168 +++++ ChibiOS_20.3.2/os/rt/include/chregistry.h | 185 ++++++ ChibiOS_20.3.2/os/rt/include/chrestrictions.h | 118 ++++ ChibiOS_20.3.2/os/rt/include/chschd.h | 716 ++++++++++++++++++++ ChibiOS_20.3.2/os/rt/include/chsem.h | 200 ++++++ ChibiOS_20.3.2/os/rt/include/chstats.h | 105 +++ ChibiOS_20.3.2/os/rt/include/chsys.h | 469 +++++++++++++ ChibiOS_20.3.2/os/rt/include/chsystypes.h | 130 ++++ ChibiOS_20.3.2/os/rt/include/chthreads.h | 440 +++++++++++++ ChibiOS_20.3.2/os/rt/include/chtime.h | 492 ++++++++++++++ ChibiOS_20.3.2/os/rt/include/chtm.h | 109 ++++ ChibiOS_20.3.2/os/rt/include/chtrace.h | 256 ++++++++ ChibiOS_20.3.2/os/rt/include/chvt.h | 362 ++++++++++ ChibiOS_20.3.2/os/rt/rt.mk | 75 +++ ChibiOS_20.3.2/os/rt/src/chcond.c | 321 +++++++++ ChibiOS_20.3.2/os/rt/src/chdebug.c | 257 ++++++++ ChibiOS_20.3.2/os/rt/src/chdynamic.c | 185 ++++++ ChibiOS_20.3.2/os/rt/src/chevents.c | 603 +++++++++++++++++ ChibiOS_20.3.2/os/rt/src/chmsg.c | 221 +++++++ ChibiOS_20.3.2/os/rt/src/chmtx.c | 537 +++++++++++++++ ChibiOS_20.3.2/os/rt/src/chregistry.c | 268 ++++++++ ChibiOS_20.3.2/os/rt/src/chschd.c | 610 +++++++++++++++++ ChibiOS_20.3.2/os/rt/src/chsem.c | 405 ++++++++++++ ChibiOS_20.3.2/os/rt/src/chstats.c | 126 ++++ ChibiOS_20.3.2/os/rt/src/chsys.c | 445 +++++++++++++ ChibiOS_20.3.2/os/rt/src/chthreads.c | 906 ++++++++++++++++++++++++++ ChibiOS_20.3.2/os/rt/src/chtm.c | 168 +++++ ChibiOS_20.3.2/os/rt/src/chtrace.c | 265 ++++++++ ChibiOS_20.3.2/os/rt/src/chvt.c | 477 ++++++++++++++ ChibiOS_20.3.2/os/rt/templates/chconf.h | 756 +++++++++++++++++++++ ChibiOS_20.3.2/os/rt/templates/meta/module.c | 80 +++ ChibiOS_20.3.2/os/rt/templates/meta/module.h | 76 +++ 41 files changed, 12088 insertions(+) create mode 100644 ChibiOS_20.3.2/os/rt/dox/rt.dox create mode 100644 ChibiOS_20.3.2/os/rt/include/ch.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chalign.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chchecks.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chcond.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chdebug.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chdynamic.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chevents.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chmsg.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chmtx.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chregistry.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chrestrictions.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chschd.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chsem.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chstats.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chsys.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chsystypes.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chthreads.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chtime.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chtm.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chtrace.h create mode 100644 ChibiOS_20.3.2/os/rt/include/chvt.h create mode 100644 ChibiOS_20.3.2/os/rt/rt.mk create mode 100644 ChibiOS_20.3.2/os/rt/src/chcond.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chdebug.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chdynamic.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chevents.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chmsg.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chmtx.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chregistry.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chschd.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chsem.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chstats.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chsys.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chthreads.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chtm.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chtrace.c create mode 100644 ChibiOS_20.3.2/os/rt/src/chvt.c create mode 100644 ChibiOS_20.3.2/os/rt/templates/chconf.h create mode 100644 ChibiOS_20.3.2/os/rt/templates/meta/module.c create mode 100644 ChibiOS_20.3.2/os/rt/templates/meta/module.h (limited to 'ChibiOS_20.3.2/os/rt') diff --git a/ChibiOS_20.3.2/os/rt/dox/rt.dox b/ChibiOS_20.3.2/os/rt/dox/rt.dox new file mode 100644 index 0000000..75030ff --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/dox/rt.dox @@ -0,0 +1,152 @@ +/* + 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 kernel RT Kernel + * @details The kernel is the portable part of ChibiOS/RT, this section + * documents the various kernel subsystems. + */ + +/** + * @defgroup kernel_info Version Numbers and Identification + * @ingroup kernel + */ + +/** + * @defgroup config_category Configuration + * @ingroup kernel + */ + +/** + * @defgroup config Options + * @ingroup config_category + */ + +/** + * @defgroup conf_checks Checks + * @ingroup config_category + */ + +/** + * @defgroup rt_restrictions Restrictions + * @ingroup config_category + */ + +/** + * @defgroup base Base Kernel Services + * @details Base kernel services, the base subsystems are always included in + * the OS builds. + * @ingroup kernel + */ + +/** + * @defgroup mem Memory Alignment + * @ingroup base + */ + +/** + * @defgroup system System Management + * @ingroup base + */ + +/** + * @defgroup scheduler Scheduler + * @ingroup base + */ + +/** + * @defgroup time_intervals Time and Intervals + * @ingroup base + */ + +/** + * @defgroup time Virtual Timers + * @ingroup base + */ + +/** + * @defgroup threads Threads + * @ingroup base + */ + +/** + * @defgroup time_measurement Time Measurement + * @ingroup base + */ + +/** + * @defgroup synchronization Synchronization + * @details Synchronization services. + * @ingroup kernel + */ + +/** + * @defgroup semaphores Counting Semaphores + * @ingroup synchronization + */ + +/** + * @defgroup mutexes Mutexes + * @ingroup synchronization + */ + +/** + * @defgroup condvars Condition Variables + * @ingroup synchronization + */ + +/** + * @defgroup events Event Flags + * @ingroup synchronization + */ + +/** + * @defgroup messages Synchronous Messages + * @ingroup synchronization + */ + +/** + * @defgroup dynamic_threads Dynamic Threads + * @ingroup kernel + */ + +/** + * @defgroup registry Registry + * @ingroup kernel + */ + +/** + * @defgroup debug Debug + * @ingroup kernel + */ + +/** + * @defgroup checks_assertions Checks and Assertions + * @ingroup debug + */ + +/** + * @defgroup trace Tracing + * @ingroup debug + */ + +/** + * @defgroup statistics Statistics + * @ingroup debug + */ diff --git a/ChibiOS_20.3.2/os/rt/include/ch.h b/ChibiOS_20.3.2/os/rt/include/ch.h new file mode 100644 index 0000000..200383b --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/ch.h @@ -0,0 +1,135 @@ +/* + 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 rt/include/ch.h + * @brief ChibiOS/RT main include file. + * + * @addtogroup kernel_info + * @details This header includes all the required kernel headers so it is the + * only kernel header you usually want to include in your application. + * @details Kernel related info. + * @{ + */ + +#ifndef CH_H +#define CH_H + +/** + * @brief ChibiOS/RT identification macro. + */ +#define _CHIBIOS_RT_ + +/** + * @brief Stable release flag. + */ +#define CH_KERNEL_STABLE 1 + +/** + * @name ChibiOS/RT version identification + * @{ + */ +/** + * @brief Kernel version string. + */ +#define CH_KERNEL_VERSION "6.1.2" + +/** + * @brief Kernel version major number. + */ +#define CH_KERNEL_MAJOR 6 + +/** + * @brief Kernel version minor number. + */ +#define CH_KERNEL_MINOR 1 + +/** + * @brief Kernel version patch number. + */ +#define CH_KERNEL_PATCH 2 +/** @} */ + +/** + * @name Constants for configuration options + */ +/** + * @brief Generic 'false' preprocessor boolean constant. + * @note It is meant to be used in configuration files as switch. + */ +#if !defined(FALSE) || defined(__DOXYGEN__) +#define FALSE 0 +#endif + +/** + * @brief Generic 'true' preprocessor boolean constant. + * @note It is meant to be used in configuration files as switch. + */ +#if !defined(TRUE) || defined(__DOXYGEN__) +#define TRUE 1 +#endif +/** @} */ + +/* Configuration headers, checks and licensing restrictions.*/ +#include "chconf.h" +#include "chchecks.h" +#include "chlicense.h" +#include "chrestrictions.h" + +/* Early function prototype required by the following headers.*/ +#ifdef __cplusplus +extern "C" { +#endif + void chSysHalt(const char *reason); +#ifdef __cplusplus +} +#endif + +/* Base kernel headers.*/ +#include "chtypes.h" /* CHTODO: Rename and rework.*/ +#include "chsystypes.h" +#include "chdebug.h" +#include "chtime.h" +#include "chalign.h" +#include "chcore.h" +#include "chtrace.h" +#include "chtm.h" +#include "chstats.h" +#include "chschd.h" +#include "chsys.h" +#include "chvt.h" +#include "chthreads.h" + +/* Optional subsystems headers.*/ +#include "chregistry.h" +#include "chsem.h" +#include "chmtx.h" +#include "chcond.h" +#include "chevents.h" +#include "chmsg.h" + +/* OSLIB.*/ +#include "chlib.h" + +/* Headers dependent on the OSLIB.*/ +#include "chdynamic.h" + +#endif /* CH_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chalign.h b/ChibiOS_20.3.2/os/rt/include/chalign.h new file mode 100644 index 0000000..56e5f1c --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chalign.h @@ -0,0 +1,120 @@ +/* + 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 rt/include/chalign.h + * @brief Memory alignment macros and structures. + * + * @addtogroup mem + * @details Memory Alignment services. + * @{ + */ + +#ifndef CHALIGN_H +#define CHALIGN_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @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) \ + /*lint -save -e9033 [10.8] The cast is safe.*/ \ + ((size_t)(p) & ~MEM_ALIGN_MASK(a)) \ + /*lint -restore*/ + +/** + * @brief Aligns to the next 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) \ + /*lint -save -e9033 [10.8] The cast is safe.*/ \ + MEM_ALIGN_PREV((size_t)(p) + MEM_ALIGN_MASK(a), (a)) \ + /*lint -restore*/ + +/** + * @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)) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHALIGN_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chchecks.h b/ChibiOS_20.3.2/os/rt/include/chchecks.h new file mode 100644 index 0000000..c2d16c0 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chchecks.h @@ -0,0 +1,263 @@ +/* + 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 rt/include/chchecks.h + * @brief Configuration file checks header. + * + * @addtogroup conf_checks + * @details This module performs a series of checks on configuration data, + * it is able to detect and reject obsolete or incomplete + * @p chconf.h files. + * @{ + */ + +#ifndef CHCHECKS_H +#define CHCHECKS_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/* Configuration file checks.*/ +#if !defined(_CHIBIOS_RT_CONF_) +#error "invalid configuration file" +#endif + +#if !defined(_CHIBIOS_RT_CONF_VER_6_1_) +#error "obsolete or unknown configuration file" +#endif + +/* System timers checks.*/ +#if !defined(CH_CFG_ST_RESOLUTION) +#error "CH_CFG_ST_RESOLUTION not defined in chconf.h" +#endif + +#if !defined(CH_CFG_ST_FREQUENCY) +#error "CH_CFG_ST_FREQUENCY not defined in chconf.h" +#endif + +#if !defined(CH_CFG_INTERVALS_SIZE) +#error "CH_CFG_INTERVALS_SIZE not defined in chconf.h" +#endif + +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#error "CH_CFG_TIME_TYPES_SIZE not defined in chconf.h" +#endif + +#if !defined(CH_CFG_ST_TIMEDELTA) +#error "CH_CFG_ST_TIMEDELTA not defined in chconf.h" +#endif + +/* Kernel parameters and options checks.*/ +#if !defined(CH_CFG_TIME_QUANTUM) +#error "CH_CFG_TIME_QUANTUM not defined in chconf.h" +#endif + +#if !defined(CH_CFG_MEMCORE_SIZE) +#error "CH_CFG_MEMCORE_SIZE not defined in chconf.h" +#endif + +#if !defined(CH_CFG_NO_IDLE_THREAD) +#error "CH_CFG_NO_IDLE_THREAD not defined in chconf.h" +#endif + +/* Performance options checks.*/ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#error "CH_CFG_OPTIMIZE_SPEED not defined in chconf.h" +#endif + +/* Subsystem options checks.*/ +#if !defined(CH_CFG_USE_TM) +#error "CH_CFG_USE_TM not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_REGISTRY) +#error "CH_CFG_USE_REGISTRY 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_SEMAPHORES) +#error "CH_CFG_USE_SEMAPHORES not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#error "CH_CFG_USE_SEMAPHORES_PRIORITY not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MUTEXES) +#error "CH_CFG_USE_MUTEXES not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#error "CH_CFG_USE_MUTEXES_RECURSIVE not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_CONDVARS) +#error "CH_CFG_USE_CONDVARS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#error "CH_CFG_USE_CONDVARS_TIMEOUT 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_EVENTS_TIMEOUT) +#error "CH_CFG_USE_EVENTS_TIMEOUT not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MESSAGES) +#error "CH_CFG_USE_MESSAGES not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#error "CH_CFG_USE_MESSAGES_PRIORITY not defined in chconf.h" +#endif + +#if !defined(CH_CFG_USE_DYNAMIC) +#error "CH_CFG_USE_DYNAMIC not defined in chconf.h" +#endif + +/* Debug options checks.*/ +#if !defined(CH_DBG_STATISTICS) +#error "CH_DBG_STATISTICS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#error "CH_DBG_SYSTEM_STATE_CHECK not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_CHECKS) +#error "CH_DBG_ENABLE_CHECKS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_ASSERTS) +#error "CH_DBG_ENABLE_ASSERTS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_TRACE_MASK) +#error "CH_DBG_TRACE_MASK not defined in chconf.h" +#endif + +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#error "CH_DBG_TRACE_BUFFER_SIZE not defined in chconf.h" +#endif + +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#error "CH_DBG_ENABLE_STACK_CHECK not defined in chconf.h" +#endif + +#if !defined(CH_DBG_FILL_THREADS) +#error "CH_DBG_FILL_THREADS not defined in chconf.h" +#endif + +#if !defined(CH_DBG_THREADS_PROFILING) +#error "CH_DBG_THREADS_PROFILING not defined in chconf.h" +#endif + +/* System hooks checks.*/ +#if !defined(CH_CFG_SYSTEM_INIT_HOOK) +#error "CH_CFG_SYSTEM_INIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_SYSTEM_EXTRA_FIELDS) +#error "CH_CFG_SYSTEM_EXTRA_FIELDS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_EXTRA_FIELDS) +#error "CH_CFG_THREAD_EXTRA_FIELDS not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_INIT_HOOK) +#error "CH_CFG_THREAD_INIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_THREAD_EXIT_HOOK) +#error "CH_CFG_THREAD_EXIT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_CONTEXT_SWITCH_HOOK) +#error "CH_CFG_CONTEXT_SWITCH_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IRQ_PROLOGUE_HOOK) +#error "CH_CFG_IRQ_PROLOGUE_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IRQ_EPILOGUE_HOOK) +#error "CH_CFG_IRQ_EPILOGUE_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IDLE_ENTER_HOOK) +#error "CH_CFG_IDLE_ENTER_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IDLE_LEAVE_HOOK) +#error "CH_CFG_IDLE_LEAVE_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_IDLE_LOOP_HOOK) +#error "CH_CFG_IDLE_LOOP_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_SYSTEM_TICK_HOOK) +#error "CH_CFG_SYSTEM_TICK_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_SYSTEM_HALT_HOOK) +#error "CH_CFG_SYSTEM_HALT_HOOK not defined in chconf.h" +#endif + +#if !defined(CH_CFG_TRACE_HOOK) +#error "CH_CFG_TRACE_HOOK not defined in chconf.h" +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHCHECKS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chcond.h b/ChibiOS_20.3.2/os/rt/include/chcond.h new file mode 100644 index 0000000..b6d7f96 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chcond.h @@ -0,0 +1,116 @@ +/* + 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 . +*/ +/* + Concepts and parts of this file have been contributed by Leon Woestenberg. + */ + +/** + * @file rt/include/chcond.h + * @brief Condition Variables macros and structures. + * + * @addtogroup condvars + * @{ + */ + +#ifndef CHCOND_H +#define CHCOND_H + +#if (CH_CFG_USE_CONDVARS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if CH_CFG_USE_MUTEXES == FALSE +#error "CH_CFG_USE_CONDVARS requires CH_CFG_USE_MUTEXES" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief condition_variable_t structure. + */ +typedef struct condition_variable { + threads_queue_t queue; /**< @brief Condition variable + threads queue. */ +} condition_variable_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Data part of a static condition variable initializer. + * @details This macro should be used when statically initializing a condition + * variable that is part of a bigger structure. + * + * @param[in] name the name of the condition variable + */ +#define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.queue)} + +/** + * @brief Static condition variable initializer. + * @details Statically initialized condition variables require no explicit + * initialization using @p chCondInit(). + * + * @param[in] name the name of the condition variable + */ +#define CONDVAR_DECL(name) condition_variable_t name = _CONDVAR_DATA(name) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chCondObjectInit(condition_variable_t *cp); + void chCondSignal(condition_variable_t *cp); + void chCondSignalI(condition_variable_t *cp); + void chCondBroadcast(condition_variable_t *cp); + void chCondBroadcastI(condition_variable_t *cp); + msg_t chCondWait(condition_variable_t *cp); + msg_t chCondWaitS(condition_variable_t *cp); +#if CH_CFG_USE_CONDVARS_TIMEOUT == TRUE + msg_t chCondWaitTimeout(condition_variable_t *cp, sysinterval_t timeout); + msg_t chCondWaitTimeoutS(condition_variable_t *cp, sysinterval_t timeout); +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CH_CFG_USE_CONDVARS == TRUE */ + +#endif /* CHCOND_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chdebug.h b/ChibiOS_20.3.2/os/rt/include/chdebug.h new file mode 100644 index 0000000..240d1ca --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chdebug.h @@ -0,0 +1,169 @@ +/* + 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 rt/include/chdebug.h + * @brief Debug support macros and structures. + * + * @addtogroup checks_assertions + * @{ + */ + +#ifndef CHDEBUG_H +#define CHDEBUG_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Debug related settings + * @{ + */ +/** + * @brief Fill value for thread stack area in debug mode. + */ +#if !defined(CH_DBG_STACK_FILL_VALUE) || defined(__DOXYGEN__) +#define CH_DBG_STACK_FILL_VALUE 0x55 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE +#define _dbg_enter_lock() (ch.dbg.lock_cnt = (cnt_t)1) +#define _dbg_leave_lock() (ch.dbg.lock_cnt = (cnt_t)0) +#endif + +/* When the state checker feature is disabled then the following functions + are replaced by an empty macro.*/ +#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 + +/** + * @name Macro Functions + * @{ + */ +/** + * @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) */ +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + void _dbg_check_disable(void); + void _dbg_check_suspend(void); + void _dbg_check_enable(void); + void _dbg_check_lock(void); + void _dbg_check_unlock(void); + void _dbg_check_lock_from_isr(void); + void _dbg_check_unlock_from_isr(void); + void _dbg_check_enter_isr(void); + void _dbg_check_leave_isr(void); + void chDbgCheckClassI(void); + void chDbgCheckClassS(void); +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHDEBUG_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chdynamic.h b/ChibiOS_20.3.2/os/rt/include/chdynamic.h new file mode 100644 index 0000000..6f44c40 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chdynamic.h @@ -0,0 +1,99 @@ +/* + 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 rt/include/chdynamic.h + * @brief Dynamic threads macros and structures. + * + * @addtogroup dynamic_threads + * @{ + */ + +#ifndef CHDYNAMIC_H +#define CHDYNAMIC_H + +#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* + * Module dependencies check. + */ +#if CH_CFG_USE_WAITEXIT == FALSE +#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT" +#endif + +#if CH_CFG_USE_REGISTRY == FALSE +#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_REGISTRY" +#endif + +#if (CH_CFG_USE_HEAP == FALSE) && (CH_CFG_USE_MEMPOOLS == FALSE) +#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/* + * Dynamic threads APIs. + */ +#ifdef __cplusplus +extern "C" { +#endif +#if CH_CFG_USE_HEAP == TRUE + thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size, + const char *name, tprio_t prio, + tfunc_t pf, void *arg); +#endif +#if CH_CFG_USE_MEMPOOLS == TRUE + thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, const char *name, + tprio_t prio, tfunc_t pf, void *arg); +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CH_CFG_USE_DYNAMIC == TRUE */ + +#endif /* CHDYNAMIC_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chevents.h b/ChibiOS_20.3.2/os/rt/include/chevents.h new file mode 100644 index 0000000..c81d51e --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chevents.h @@ -0,0 +1,291 @@ +/* + 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 . +*/ +/* + Concepts and parts of this file have been contributed by Scott (skute). + */ + +/** + * @file rt/include/chevents.h + * @brief Events macros and structures. + * + * @addtogroup events + * @{ + */ + +#ifndef CHEVENTS_H +#define CHEVENTS_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) + +/*===========================================================================*/ +/* 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); +#if (CH_CFG_OPTIMIZE_SPEED == TRUE) || (CH_CFG_USE_EVENTS_TIMEOUT == FALSE) + eventmask_t chEvtWaitOne(eventmask_t events); + eventmask_t chEvtWaitAny(eventmask_t events); + eventmask_t chEvtWaitAll(eventmask_t events); +#endif +#if CH_CFG_USE_EVENTS_TIMEOUT == TRUE + eventmask_t chEvtWaitOneTimeout(eventmask_t events, sysinterval_t timeout); + eventmask_t chEvtWaitAnyTimeout(eventmask_t events, sysinterval_t timeout); + eventmask_t chEvtWaitAllTimeout(eventmask_t events, sysinterval_t timeout); +#endif +#ifdef __cplusplus +} +#endif + +#if (CH_CFG_OPTIMIZE_SPEED == FALSE) && (CH_CFG_USE_EVENTS_TIMEOUT == TRUE) +#define chEvtWaitOne(mask) chEvtWaitOneTimeout(mask, TIME_INFINITE) +#define chEvtWaitAny(mask) chEvtWaitAnyTimeout(mask, TIME_INFINITE) +#define chEvtWaitAll(mask) chEvtWaitAllTimeout(mask, TIME_INFINITE) +#endif + +/*===========================================================================*/ +/* Module inline 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 + */ +static inline void chEvtObjectInit(event_source_t *esp) { + + esp->next = (event_listener_t *)esp; +} + +/** + * @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 + */ +static inline void chEvtRegisterMask(event_source_t *esp, + event_listener_t *elp, + eventmask_t 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 + */ +static inline void chEvtRegister(event_source_t *esp, + event_listener_t *elp, + eventid_t 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 + */ +static inline bool chEvtIsListeningI(event_source_t *esp) { + + return (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 + */ +static inline void chEvtBroadcast(event_source_t *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 + */ +static inline void chEvtBroadcastI(event_source_t *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 + */ +static inline eventmask_t chEvtAddEventsI(eventmask_t events) { + + return currp->epending |= 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 + */ +static inline eventmask_t chEvtGetEventsX(void) { + + return currp->epending; +} + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +#endif /* CHEVENTS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chmsg.h b/ChibiOS_20.3.2/os/rt/include/chmsg.h new file mode 100644 index 0000000..6bd110a --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chmsg.h @@ -0,0 +1,212 @@ +/* + 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 rt/include/chmsg.h + * @brief Messages macros and structures. + * + * @addtogroup 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. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + msg_t chMsgSend(thread_t *tp, msg_t msg); + thread_t *chMsgWaitS(void); + thread_t *chMsgWaitTimeoutS(sysinterval_t timeout); + thread_t *chMsgPollS(void); + void chMsgRelease(thread_t *tp, msg_t msg); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/** + * @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 + */ +static inline 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 + */ +static inline thread_t *chMsgWaitTimeout(sysinterval_t timeout) { + thread_t *tp; + + chSysLock(); + tp = chMsgWaitTimeoutS(timeout); + chSysUnlock(); + + return tp; +} + +/** + * @brief Poll to check for an incoming message. + * @post If a message is available 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. + * @retval NULL if no incoming message waiting. + * + * @api + */ +static inline thread_t *chMsgPoll(void) { + thread_t *tp; + + chSysLock(); + tp = chMsgPollS(); + chSysUnlock(); + + return tp; +} + +/** + * @brief Evaluates to @p true if the thread has pending messages. + * + * @param[in] tp pointer to the thread + * @return The pending messages status. + * + * @iclass + */ +static inline bool chMsgIsPendingI(thread_t *tp) { + + chDbgCheckClassI(); + + return (bool)(tp->msgqueue.next != (thread_t *)&tp->msgqueue); +} + +/** + * @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 + */ +static inline msg_t chMsgGet(thread_t *tp) { + + chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state"); + + return tp->u.sentmsg; +} + +/** + * @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 + */ +static inline void chMsgReleaseS(thread_t *tp, msg_t msg) { + + chDbgCheckClassS(); + + chSchWakeupS(tp, msg); +} + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +#endif /* CHMSG_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chmtx.h b/ChibiOS_20.3.2/os/rt/include/chmtx.h new file mode 100644 index 0000000..6fa17f7 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chmtx.h @@ -0,0 +1,168 @@ +/* + 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 rt/include/chmtx.h + * @brief Mutexes macros and structures. + * + * @addtogroup mutexes + * @{ + */ + +#ifndef CHMTX_H +#define CHMTX_H + +#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a mutex structure. + */ +typedef struct ch_mutex mutex_t; + +/** + * @brief Mutex structure. + */ +struct ch_mutex { + threads_queue_t queue; /**< @brief Queue of the threads sleeping + on this mutex. */ + thread_t *owner; /**< @brief Owner @p thread_t pointer or + @p NULL. */ + mutex_t *next; /**< @brief Next @p mutex_t into an + owner-list or @p NULL. */ +#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__) + cnt_t cnt; /**< @brief Mutex recursion counter. */ +#endif +}; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Data part of a static mutex initializer. + * @details This macro should be used when statically initializing a mutex + * that is part of a bigger structure. + * + * @param[in] name the name of the mutex variable + */ +#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__) +#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL, 0} +#else +#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL} +#endif + +/** + * @brief Static mutex initializer. + * @details Statically initialized mutexes require no explicit initialization + * using @p chMtxInit(). + * + * @param[in] name the name of the mutex variable + */ +#define MUTEX_DECL(name) mutex_t name = _MUTEX_DATA(name) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chMtxObjectInit(mutex_t *mp); + void chMtxLock(mutex_t *mp); + void chMtxLockS(mutex_t *mp); + bool chMtxTryLock(mutex_t *mp); + bool chMtxTryLockS(mutex_t *mp); + void chMtxUnlock(mutex_t *mp); + void chMtxUnlockS(mutex_t *mp); + void chMtxUnlockAll(void); + void chMtxUnlockAllS(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @brief Returns @p true if the mutex queue contains at least a waiting + * thread. + * + * @param[out] mp pointer to a @p mutex_t structure + * @return The mutex queue status. + * + * @sclass + */ +static inline bool chMtxQueueNotEmptyS(mutex_t *mp) { + + chDbgCheckClassS(); + + return queue_notempty(&mp->queue); +} + +/** + * @brief Returns the mutex owner thread. + * + * @param[out] mp pointer to a @p mutex_t structure + * @return The owner thread. + * @retval NULL if the mutex is not owned. + * + * @iclass + */ +static inline thread_t *chMtxGetOwnerI(mutex_t *mp) { + + chDbgCheckClassI(); + + return mp->owner; +} + +/** + * @brief Returns the next mutex in the mutexes stack of the current thread. + * + * @return A pointer to the next mutex in the stack. + * @retval NULL if the stack is empty. + * + * @xclass + */ +static inline mutex_t *chMtxGetNextMutexX(void) { + + return chThdGetSelfX()->mtxlist; +} + +#endif /* CH_CFG_USE_MUTEXES == TRUE */ + +#endif /* CHMTX_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chregistry.h b/ChibiOS_20.3.2/os/rt/include/chregistry.h new file mode 100644 index 0000000..4c36fe7 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chregistry.h @@ -0,0 +1,185 @@ +/* + 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 rt/include/chregistry.h + * @brief Threads registry macros and structures. + * + * @addtogroup registry + * @{ + */ + +#ifndef CHREGISTRY_H +#define CHREGISTRY_H + +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ChibiOS/RT memory signature record. + */ +typedef struct { + char identifier[4]; /**< @brief Always set to "main". */ + uint8_t zero; /**< @brief Must be zero. */ + uint8_t size; /**< @brief Size of this structure. */ + uint16_t version; /**< @brief Encoded ChibiOS/RT version. */ + uint8_t ptrsize; /**< @brief Size of a pointer. */ + uint8_t timesize; /**< @brief Size of a @p systime_t. */ + uint8_t threadsize; /**< @brief Size of a @p thread_t. */ + uint8_t off_prio; /**< @brief Offset of @p prio field. */ + uint8_t off_ctx; /**< @brief Offset of @p ctx field. */ + uint8_t off_newer; /**< @brief Offset of @p newer field. */ + uint8_t off_older; /**< @brief Offset of @p older field. */ + uint8_t off_name; /**< @brief Offset of @p name field. */ + uint8_t off_stklimit; /**< @brief Offset of @p stklimit field.*/ + uint8_t off_state; /**< @brief Offset of @p state field. */ + uint8_t off_flags; /**< @brief Offset of @p flags field. */ + uint8_t off_refs; /**< @brief Offset of @p refs field. */ + uint8_t off_preempt; /**< @brief Offset of @p preempt field. */ + uint8_t off_time; /**< @brief Offset of @p time field. */ +} chdebug_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Removes a thread from the registry list. + * @note This macro is not meant for use in application code. + * + * @param[in] tp thread to remove from the registry + */ +#define REG_REMOVE(tp) { \ + (tp)->older->newer = (tp)->newer; \ + (tp)->newer->older = (tp)->older; \ +} + +/** + * @brief Adds a thread to the registry list. + * @note This macro is not meant for use in application code. + * + * @param[in] tp thread to add to the registry + */ +#define REG_INSERT(tp) { \ + (tp)->newer = (thread_t *)&ch.rlist; \ + (tp)->older = ch.rlist.older; \ + (tp)->older->newer = (tp); \ + ch.rlist.older = (tp); \ +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + extern ROMCONST chdebug_t ch_debug; + thread_t *chRegFirstThread(void); + thread_t *chRegNextThread(thread_t *tp); + thread_t *chRegFindThreadByName(const char *name); + thread_t *chRegFindThreadByPointer(thread_t *tp); + thread_t *chRegFindThreadByWorkingArea(stkalign_t *wa); +#ifdef __cplusplus +} +#endif + +#endif /* CH_CFG_USE_REGISTRY == TRUE */ + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @brief Sets the current thread name. + * @pre This function only stores the pointer to the name if the option + * @p CH_CFG_USE_REGISTRY is enabled else no action is performed. + * + * @param[in] name thread name as a zero terminated string + * + * @api + */ +static inline void chRegSetThreadName(const char *name) { + +#if CH_CFG_USE_REGISTRY == TRUE + ch.rlist.current->name = name; +#else + (void)name; +#endif +} + +/** + * @brief Returns the name of the specified thread. + * @pre This function only returns the pointer to the name if the option + * @p CH_CFG_USE_REGISTRY is enabled else @p NULL is returned. + * + * @param[in] tp pointer to the thread + * + * @return Thread name as a zero terminated string. + * @retval NULL if the thread name has not been set. + * + */ +static inline const char *chRegGetThreadNameX(thread_t *tp) { + +#if CH_CFG_USE_REGISTRY == TRUE + return tp->name; +#else + (void)tp; + return NULL; +#endif +} + +/** + * @brief Changes the name of the specified thread. + * @pre This function only stores the pointer to the name if the option + * @p CH_CFG_USE_REGISTRY is enabled else no action is performed. + * + * @param[in] tp pointer to the thread + * @param[in] name thread name as a zero terminated string + * + * @xclass + */ +static inline void chRegSetThreadNameX(thread_t *tp, const char *name) { + +#if CH_CFG_USE_REGISTRY == TRUE + tp->name = name; +#else + (void)tp; + (void)name; +#endif +} + +#endif /* CHREGISTRY_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chrestrictions.h b/ChibiOS_20.3.2/os/rt/include/chrestrictions.h new file mode 100644 index 0000000..7c1840f --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chrestrictions.h @@ -0,0 +1,118 @@ +/* + 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 rt/include/chrestrictions.h + * @brief Licensing restrictions header. + * + * @addtogroup rt_restrictions + * @details This module is responsible for applying license-related + * restrictions to the configuration options. + * @{ + */ + +#ifndef CHRESTRICTIONS_H +#define CHRESTRICTIONS_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/* License checks.*/ +#if !defined(CH_CUSTOMER_LIC_RT) || !defined(CH_LICENSE_FEATURES) +#error "malformed chlicense.h" +#endif + +#if CH_CUSTOMER_LIC_RT == FALSE +#error "ChibiOS/RT 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 + +/* Restricted subsystems.*/ +#undef CH_DBG_STATISTICS +#undef CH_DBG_TRACE_MASK + +#define CH_DBG_STATISTICS FALSE +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED + +#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 + +/* Restricted subsystems.*/ +#undef CH_CFG_USE_TM +#undef CH_CFG_USE_MUTEXES +#undef CH_CFG_USE_CONDVARS +#undef CH_CFG_USE_DYNAMIC + +#define CH_CFG_USE_TM FALSE +#define CH_CFG_USE_MUTEXES FALSE +#define CH_CFG_USE_CONDVARS FALSE +#define CH_CFG_USE_DYNAMIC FALSE + +#endif /* CH_LICENSE_FEATURES == CH_FEATURES_BASIC */ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHRESTRICTIONS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chschd.h b/ChibiOS_20.3.2/os/rt/include/chschd.h new file mode 100644 index 0000000..edff108 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chschd.h @@ -0,0 +1,716 @@ +/* + 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 rt/include/chschd.h + * @brief Scheduler macros and structures. + * + * @addtogroup scheduler + * @{ + */ + +#ifndef CHSCHD_H +#define CHSCHD_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @name Wakeup status codes + * @{ + */ +#define MSG_OK (msg_t)0 /**< @brief Normal wakeup message. */ +#define MSG_TIMEOUT (msg_t)-1 /**< @brief Wakeup caused by a timeout + condition. */ +#define MSG_RESET (msg_t)-2 /**< @brief Wakeup caused by a reset + condition. */ +/** @} */ + +/** + * @name Priority constants + * @{ + */ +#define NOPRIO (tprio_t)0 /**< @brief Ready list header + priority. */ +#define IDLEPRIO (tprio_t)1 /**< @brief Idle priority. */ +#define LOWPRIO (tprio_t)2 /**< @brief Lowest priority. */ +#define NORMALPRIO (tprio_t)128 /**< @brief Normal priority. */ +#define HIGHPRIO (tprio_t)255 /**< @brief Highest priority. */ +/** @} */ + +/** + * @name Thread states + * @{ + */ +#define CH_STATE_READY (tstate_t)0 /**< @brief Waiting on the + ready list. */ +#define CH_STATE_CURRENT (tstate_t)1 /**< @brief Currently running. */ +#define CH_STATE_WTSTART (tstate_t)2 /**< @brief Just created. */ +#define CH_STATE_SUSPENDED (tstate_t)3 /**< @brief Suspended state. */ +#define CH_STATE_QUEUED (tstate_t)4 /**< @brief On a queue. */ +#define CH_STATE_WTSEM (tstate_t)5 /**< @brief On a semaphore. */ +#define CH_STATE_WTMTX (tstate_t)6 /**< @brief On a mutex. */ +#define CH_STATE_WTCOND (tstate_t)7 /**< @brief On a cond.variable.*/ +#define CH_STATE_SLEEPING (tstate_t)8 /**< @brief Sleeping. */ +#define CH_STATE_WTEXIT (tstate_t)9 /**< @brief Waiting a thread. */ +#define CH_STATE_WTOREVT (tstate_t)10 /**< @brief One event. */ +#define CH_STATE_WTANDEVT (tstate_t)11 /**< @brief Several events. */ +#define CH_STATE_SNDMSGQ (tstate_t)12 /**< @brief Sending a message, + in queue. */ +#define CH_STATE_SNDMSG (tstate_t)13 /**< @brief Sent a message, + waiting answer. */ +#define CH_STATE_WTMSG (tstate_t)14 /**< @brief Waiting for a + message. */ +#define CH_STATE_FINAL (tstate_t)15 /**< @brief Thread terminated. */ + +/** + * @brief Thread states as array of strings. + * @details Each element in an array initialized with this macro can be + * indexed using the numeric thread state values. + */ +#define CH_STATE_NAMES \ + "READY", "CURRENT", "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", \ + "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", \ + "SNDMSG", "WTMSG", "FINAL" +/** @} */ + +/** + * @name Thread flags and attributes + * @{ + */ +#define CH_FLAG_MODE_MASK (tmode_t)3U /**< @brief Thread memory mode + mask. */ +#define CH_FLAG_MODE_STATIC (tmode_t)0U /**< @brief Static thread. */ +#define CH_FLAG_MODE_HEAP (tmode_t)1U /**< @brief Thread allocated + from a Memory Heap. */ +#define CH_FLAG_MODE_MPOOL (tmode_t)2U /**< @brief Thread allocated + from a Memory Pool. */ +#define CH_FLAG_TERMINATE (tmode_t)4U /**< @brief Termination requested + flag. */ +/** @} */ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Generic threads single link list, it works like a stack. + */ +struct ch_threads_list { + thread_t *next; /**< @brief Next in the list/queue. */ +}; + +/** + * @brief Generic threads bidirectional linked list header and element. + */ +struct ch_threads_queue { + thread_t *next; /**< @brief Next in the list/queue. */ + thread_t *prev; /**< @brief Previous in the queue. */ +}; + +/** + * @brief Structure representing a thread. + * @note Not all the listed fields are always needed, by switching off some + * not needed ChibiOS/RT subsystems it is possible to save RAM space + * by shrinking this structure. + */ +struct ch_thread { + threads_queue_t queue; /**< @brief Threads queue header. */ + tprio_t prio; /**< @brief Thread priority. */ + struct port_context ctx; /**< @brief Processor context. */ +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + thread_t *newer; /**< @brief Newer registry element. */ + thread_t *older; /**< @brief Older registry element. */ +#endif + /* End of the fields shared with the ReadyList structure. */ +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + /** + * @brief Thread name or @p NULL. + */ + const char *name; +#endif +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \ + defined(__DOXYGEN__) + /** + * @brief Working area base address. + * @note This pointer is used for stack overflow checks and for + * dynamic threading. + */ + stkalign_t *wabase; +#endif + /** + * @brief Current thread state. + */ + tstate_t state; + /** + * @brief Various thread flags. + */ + tmode_t flags; +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + /** + * @brief References to this thread. + */ + trefs_t refs; +#endif + /** + * @brief Number of ticks remaining to this thread. + */ +#if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__) + tslices_t ticks; +#endif +#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__) + /** + * @brief Thread consumed time in ticks. + * @note This field can overflow. + */ + volatile systime_t time; +#endif + /** + * @brief State-specific fields. + * @note All the fields declared in this union are only valid in the + * specified state or condition and are thus volatile. + */ + union { + /** + * @brief Thread wakeup code. + * @note This field contains the low level message sent to the thread + * by the waking thread or interrupt handler. The value is valid + * after exiting the @p chSchWakeupS() function. + */ + msg_t rdymsg; + /** + * @brief Thread exit code. + * @note The thread termination code is stored in this field in order + * to be retrieved by the thread performing a @p chThdWait() on + * this thread. + */ + msg_t exitcode; + /** + * @brief Pointer to a generic "wait" object. + * @note This field is used to get a generic pointer to a synchronization + * object and is valid when the thread is in one of the wait + * states. + */ + void *wtobjp; + /** + * @brief Pointer to a generic thread reference object. + * @note This field is used to get a pointer to a synchronization + * object and is valid when the thread is in @p CH_STATE_SUSPENDED + * state. + */ + thread_reference_t *wttrp; +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + /** + * @brief Thread sent message. + */ + msg_t sentmsg; +#endif +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + /** + * @brief Pointer to a generic semaphore object. + * @note This field is used to get a pointer to a synchronization + * object and is valid when the thread is in @p CH_STATE_WTSEM + * state. + */ + struct ch_semaphore *wtsemp; +#endif +#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) + /** + * @brief Pointer to a generic mutex object. + * @note This field is used to get a pointer to a synchronization + * object and is valid when the thread is in @p CH_STATE_WTMTX + * state. + */ + struct ch_mutex *wtmtxp; +#endif +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + /** + * @brief Enabled events mask. + * @note This field is only valid while the thread is in the + * @p CH_STATE_WTOREVT or @p CH_STATE_WTANDEVT states. + */ + eventmask_t ewmask; +#endif + } u; +#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Termination waiting list. + */ + threads_list_t waiting; +#endif +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + /** + * @brief Messages queue. + */ + threads_queue_t msgqueue; +#endif +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + /** + * @brief Pending events mask. + */ + eventmask_t epending; +#endif +#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) + /** + * @brief List of the mutexes owned by this thread. + * @note The list is terminated by a @p NULL in this field. + */ + struct ch_mutex *mtxlist; + /** + * @brief Thread's own, non-inherited, priority. + */ + tprio_t realprio; +#endif +#if ((CH_CFG_USE_DYNAMIC == TRUE) && (CH_CFG_USE_MEMPOOLS == TRUE)) || \ + defined(__DOXYGEN__) + /** + * @brief Memory Pool where the thread workspace is returned. + */ + void *mpool; +#endif +#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) + /** + * @brief Thread statistics. + */ + time_measurement_t stats; +#endif +#if defined(CH_CFG_THREAD_EXTRA_FIELDS) + /* Extra fields defined in chconf.h.*/ + CH_CFG_THREAD_EXTRA_FIELDS +#endif +}; + +/** + * @extends virtual_timers_list_t + * + * @brief Virtual Timer descriptor structure. + */ +struct ch_virtual_timer { + virtual_timer_t *next; /**< @brief Next timer in the list. */ + virtual_timer_t *prev; /**< @brief Previous timer in the list. */ + sysinterval_t delta; /**< @brief Time delta before timeout. */ + vtfunc_t func; /**< @brief Timer callback function + pointer. */ + void *par; /**< @brief Timer callback function + parameter. */ +}; + +/** + * @brief Virtual timers list header. + * @note The timers list is implemented as a double link bidirectional list + * in order to make the unlink time constant, the reset of a virtual + * timer is often used in the code. + */ +struct ch_virtual_timers_list { + virtual_timer_t *next; /**< @brief Next timer in the delta + list. */ + virtual_timer_t *prev; /**< @brief Last timer in the delta + list. */ + sysinterval_t delta; /**< @brief Must be initialized to -1. */ +#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) + volatile systime_t systime; /**< @brief System Time counter. */ +#endif +#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) + /** + * @brief System time of the last tick event. + */ + systime_t lasttime; /**< @brief System time of the last + tick event. */ +#endif +}; + +/** + * @extends threads_queue_t + */ +struct ch_ready_list { + threads_queue_t queue; /**< @brief Threads queue. */ + tprio_t prio; /**< @brief This field must be + initialized to zero. */ + struct port_context ctx; /**< @brief Not used, present because + offsets. */ +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + thread_t *newer; /**< @brief Newer registry element. */ + thread_t *older; /**< @brief Older registry element. */ +#endif + /* End of the fields shared with the thread_t structure.*/ + thread_t *current; /**< @brief The currently running + thread. */ +}; + +/** + * @brief System debug data structure. + */ +struct ch_system_debug { + /** + * @brief Pointer to the panic message. + * @details This pointer is meant to be accessed through the debugger, it is + * written once and then the system is halted. + * @note Accesses to this pointer must never be optimized out so the + * field itself is declared volatile. + */ + const char * volatile panic_msg; +#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 (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) + /** + * @brief Public trace buffer. + */ + ch_trace_buffer_t trace_buffer; +#endif +}; + +/** + * @brief System data structure. + * @note This structure contain all the data areas used by the OS except + * stacks. + */ +struct ch_system { + /** + * @brief Ready list header. + */ + ready_list_t rlist; + /** + * @brief Virtual timers delta list header. + */ + virtual_timers_list_t vtlist; + /** + * @brief System debug. + */ + system_debug_t dbg; + /** + * @brief Main thread descriptor. + */ + thread_t mainthread; +#if (CH_CFG_USE_TM == TRUE) || defined(__DOXYGEN__) + /** + * @brief Time measurement calibration data. + */ + tm_calibration_t tm; +#endif +#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) + /** + * @brief Global kernel statistics. + */ + kernel_stats_t kernel_stats; +#endif + CH_CFG_SYSTEM_EXTRA_FIELDS +}; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the priority of the first thread on the given ready list. + * + * @notapi + */ +#define firstprio(rlp) ((rlp)->next->prio) + +/** + * @brief Current thread pointer access macro. + * @note This macro is not meant to be used in the application code but + * only from within the kernel, use @p chThdGetSelfX() instead. + */ +#define currp ch.rlist.current + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern ch_system_t ch; +#endif + +/* + * Scheduler APIs. + */ +#ifdef __cplusplus +extern "C" { +#endif + void _scheduler_init(void); + thread_t *chSchReadyI(thread_t *tp); + thread_t *chSchReadyAheadI(thread_t *tp); + void chSchGoSleepS(tstate_t newstate); + msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout); + void chSchWakeupS(thread_t *ntp, msg_t msg); + void chSchRescheduleS(void); + bool chSchIsPreemptionRequired(void); + void chSchDoRescheduleBehind(void); + void chSchDoRescheduleAhead(void); + void chSchDoReschedule(void); +#if CH_CFG_OPTIMIZE_SPEED == FALSE + void queue_prio_insert(thread_t *tp, threads_queue_t *tqp); + void queue_insert(thread_t *tp, threads_queue_t *tqp); + thread_t *queue_fifo_remove(threads_queue_t *tqp); + thread_t *queue_lifo_remove(threads_queue_t *tqp); + thread_t *queue_dequeue(thread_t *tp); + void list_insert(thread_t *tp, threads_list_t *tlp); + thread_t *list_remove(threads_list_t *tlp); +#endif /* CH_CFG_OPTIMIZE_SPEED == FALSE */ +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @brief Threads list initialization. + * + * @param[in] tlp pointer to the threads list object + * + * @notapi + */ +static inline void list_init(threads_list_t *tlp) { + + tlp->next = (thread_t *)tlp; +} + +/** + * @brief Evaluates to @p true if the specified threads list is empty. + * + * @param[in] tlp pointer to the threads list object + * @return The status of the list. + * + * @notapi + */ +static inline bool list_isempty(threads_list_t *tlp) { + + return (bool)(tlp->next == (thread_t *)tlp); +} + +/** + * @brief Evaluates to @p true if the specified threads list is not empty. + * + * @param[in] tlp pointer to the threads list object + * @return The status of the list. + * + * @notapi + */ +static inline bool list_notempty(threads_list_t *tlp) { + + return (bool)(tlp->next != (thread_t *)tlp); +} + +/** + * @brief Threads queue initialization. + * + * @param[in] tqp pointer to the threads queue object + * + * @notapi + */ +static inline void queue_init(threads_queue_t *tqp) { + + tqp->next = (thread_t *)tqp; + tqp->prev = (thread_t *)tqp; +} + +/** + * @brief Evaluates to @p true if the specified threads queue is empty. + * + * @param[in] tqp pointer to the threads queue object + * @return The status of the queue. + * + * @notapi + */ +static inline bool queue_isempty(const threads_queue_t *tqp) { + + return (bool)(tqp->next == (const thread_t *)tqp); +} + +/** + * @brief Evaluates to @p true if the specified threads queue is not empty. + * + * @param[in] tqp pointer to the threads queue object + * @return The status of the queue. + * + * @notapi + */ +static inline bool queue_notempty(const threads_queue_t *tqp) { + + return (bool)(tqp->next != (const thread_t *)tqp); +} + +/* If the performance code path has been chosen then all the following + functions are inlined into the various kernel modules.*/ +#if CH_CFG_OPTIMIZE_SPEED == TRUE +static inline void list_insert(thread_t *tp, threads_list_t *tlp) { + + tp->queue.next = tlp->next; + tlp->next = tp; +} + +static inline thread_t *list_remove(threads_list_t *tlp) { + + thread_t *tp = tlp->next; + tlp->next = tp->queue.next; + + return tp; +} + +static inline void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) { + + thread_t *cp = (thread_t *)tqp; + do { + cp = cp->queue.next; + } while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio)); + tp->queue.next = cp; + tp->queue.prev = cp->queue.prev; + tp->queue.prev->queue.next = tp; + cp->queue.prev = tp; +} + +static inline void queue_insert(thread_t *tp, threads_queue_t *tqp) { + + tp->queue.next = (thread_t *)tqp; + tp->queue.prev = tqp->prev; + tp->queue.prev->queue.next = tp; + tqp->prev = tp; +} + +static inline thread_t *queue_fifo_remove(threads_queue_t *tqp) { + thread_t *tp = tqp->next; + + tqp->next = tp->queue.next; + tqp->next->queue.prev = (thread_t *)tqp; + + return tp; +} + +static inline thread_t *queue_lifo_remove(threads_queue_t *tqp) { + thread_t *tp = tqp->prev; + + tqp->prev = tp->queue.prev; + tqp->prev->queue.next = (thread_t *)tqp; + + return tp; +} + +static inline thread_t *queue_dequeue(thread_t *tp) { + + tp->queue.prev->queue.next = tp->queue.next; + tp->queue.next->queue.prev = tp->queue.prev; + + return tp; +} +#endif /* CH_CFG_OPTIMIZE_SPEED == TRUE */ + +/** + * @brief Determines if the current thread must reschedule. + * @details This function returns @p true if there is a ready thread with + * higher priority. + * + * @return The priorities situation. + * @retval false if rescheduling is not necessary. + * @retval true if there is a ready thread at higher priority. + * + * @iclass + */ +static inline bool chSchIsRescRequiredI(void) { + + chDbgCheckClassI(); + + return firstprio(&ch.rlist.queue) > currp->prio; +} + +/** + * @brief Determines if yielding is possible. + * @details This function returns @p true if there is a ready thread with + * equal or higher priority. + * + * @return The priorities situation. + * @retval false if yielding is not possible. + * @retval true if there is a ready thread at equal or higher priority. + * + * @sclass + */ +static inline bool chSchCanYieldS(void) { + + chDbgCheckClassS(); + + return firstprio(&ch.rlist.queue) >= currp->prio; +} + +/** + * @brief Yields the time slot. + * @details Yields the CPU control to the next thread in the ready list with + * equal or higher priority, if any. + * + * @sclass + */ +static inline void chSchDoYieldS(void) { + + chDbgCheckClassS(); + + if (chSchCanYieldS()) { + chSchDoRescheduleBehind(); + } +} + +/** + * @brief Inline-able preemption code. + * @details This is the common preemption code, this function must be invoked + * exclusively from the port layer. + * + * @special + */ +static inline void chSchPreemption(void) { + tprio_t p1 = firstprio(&ch.rlist.queue); + tprio_t p2 = currp->prio; + +#if CH_CFG_TIME_QUANTUM > 0 + if (currp->ticks > (tslices_t)0) { + if (p1 > p2) { + chSchDoRescheduleAhead(); + } + } + else { + if (p1 >= p2) { + chSchDoRescheduleBehind(); + } + } +#else /* CH_CFG_TIME_QUANTUM == 0 */ + if (p1 > p2) { + chSchDoRescheduleAhead(); + } +#endif /* CH_CFG_TIME_QUANTUM == 0 */ +} + +#endif /* CHSCHD_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chsem.h b/ChibiOS_20.3.2/os/rt/include/chsem.h new file mode 100644 index 0000000..62406ee --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chsem.h @@ -0,0 +1,200 @@ +/* + 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 rt/include/chsem.h + * @brief Semaphores macros and structures. + * + * @addtogroup 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. */ +/*===========================================================================*/ + +/** + * @brief Semaphore structure. + */ +typedef struct ch_semaphore { + threads_queue_t queue; /**< @brief Queue of the threads sleeping + on this semaphore. */ + cnt_t cnt; /**< @brief The semaphore counter. */ +} semaphore_t; + +/*===========================================================================*/ +/* Module 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) {_THREADS_QUEUE_DATA(name.queue), 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) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chSemObjectInit(semaphore_t *sp, cnt_t n); + void chSemResetWithMessage(semaphore_t *sp, cnt_t n, msg_t msg); + void chSemResetWithMessageI(semaphore_t *sp, cnt_t n, msg_t msg); + msg_t chSemWait(semaphore_t *sp); + msg_t chSemWaitS(semaphore_t *sp); + 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 chSemAddCounterI(semaphore_t *sp, cnt_t n); + msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @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 + */ +static inline void chSemReset(semaphore_t *sp, cnt_t 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 + */ +static inline void chSemResetI(semaphore_t *sp, cnt_t n) { + + chSemResetWithMessageI(sp, n, MSG_RESET); +} + +/** + * @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 + */ +static inline void chSemFastWaitI(semaphore_t *sp) { + + chDbgCheckClassI(); + + 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 + */ +static inline void chSemFastSignalI(semaphore_t *sp) { + + chDbgCheckClassI(); + + sp->cnt++; +} + +/** + * @brief Returns the semaphore counter current value. + * + * @param[in] sp pointer to a @p semaphore_t structure + * @return The semaphore counter value. + * + * @iclass + */ +static inline cnt_t chSemGetCounterI(const semaphore_t *sp) { + + chDbgCheckClassI(); + + return sp->cnt; +} + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +#endif /* CHSEM_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chstats.h b/ChibiOS_20.3.2/os/rt/include/chstats.h new file mode 100644 index 0000000..7225ea1 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chstats.h @@ -0,0 +1,105 @@ +/* + 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 rt/include/chstats.h + * @brief Statistics module macros and structures. + * + * @addtogroup statistics + * @{ + */ + +#ifndef CHSTATS_H +#define CHSTATS_H + +#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +#if CH_CFG_USE_TM == FALSE +#error "CH_DBG_STATISTICS requires CH_CFG_USE_TM" +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a kernel statistics structure. + */ +typedef struct { + ucnt_t n_irq; /**< @brief Number of IRQs. */ + ucnt_t n_ctxswc; /**< @brief Number of context switches. */ + time_measurement_t m_crit_thd; /**< @brief Measurement of threads + critical zones duration. */ + time_measurement_t m_crit_isr; /**< @brief Measurement of ISRs critical + zones duration. */ +} kernel_stats_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void _stats_init(void); + void _stats_increase_irq(void); + void _stats_ctxswc(thread_t *ntp, thread_t *otp); + void _stats_start_measure_crit_thd(void); + void _stats_stop_measure_crit_thd(void); + void _stats_start_measure_crit_isr(void); + void _stats_stop_measure_crit_isr(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#else /* CH_DBG_STATISTICS == FALSE */ + +/* Stub functions for when the statistics module is disabled. */ +#define _stats_increase_irq() +#define _stats_ctxswc(old, new) +#define _stats_start_measure_crit_thd() +#define _stats_stop_measure_crit_thd() +#define _stats_start_measure_crit_isr() +#define _stats_stop_measure_crit_isr() + +#endif /* CH_DBG_STATISTICS == FALSE */ + +#endif /* CHSTATS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chsys.h b/ChibiOS_20.3.2/os/rt/include/chsys.h new file mode 100644 index 0000000..afd2f36 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chsys.h @@ -0,0 +1,469 @@ +/* + 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 rt/include/chsys.h + * @brief System related macros and structures. + * + * @addtogroup system + * @{ + */ + +#ifndef CHSYS_H +#define CHSYS_H + +/*lint -sem(chSysHalt, r_no)*/ + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @name Masks of executable integrity checks. + * @{ + */ +#define CH_INTEGRITY_RLIST 1U +#define CH_INTEGRITY_VTLIST 2U +#define CH_INTEGRITY_REGISTRY 4U +#define CH_INTEGRITY_PORT 8U +/** @} */ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @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(); \ + CH_CFG_IRQ_PROLOGUE_HOOK(); \ + _stats_increase_irq(); \ + _trace_isr_enter(__func__); \ + _dbg_check_enter_isr() + +/** + * @brief IRQ handler exit code. + * @note Usually IRQ handlers function are also declared naked. + * @note This macro usually performs the final reschedule by using + * @p chSchIsPreemptionRequired() and @p chSchDoReschedule(). + * + * @special + */ +#define CH_IRQ_EPILOGUE() \ + _dbg_check_leave_isr(); \ + _trace_isr_leave(__func__); \ + CH_CFG_IRQ_EPILOGUE_HOOK(); \ + 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 for the realtime counter + * @{ + */ +/** + * @brief Seconds to realtime counter. + * @details Converts from seconds to realtime counter cycles. + * @note The macro assumes that @p freq >= @p 1. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] sec number of seconds + * @return The number of cycles. + * + * @api + */ +#define S2RTC(freq, sec) ((freq) * (sec)) + +/** + * @brief Milliseconds to realtime counter. + * @details Converts from milliseconds to realtime counter cycles. + * @note The result is rounded upward to the next millisecond boundary. + * @note The macro assumes that @p freq >= @p 1000. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] msec number of milliseconds + * @return The number of cycles. + * + * @api + */ +#define MS2RTC(freq, msec) (rtcnt_t)((((freq) + 999UL) / 1000UL) * (msec)) + +/** + * @brief Microseconds to realtime counter. + * @details Converts from microseconds to realtime counter cycles. + * @note The result is rounded upward to the next microsecond boundary. + * @note The macro assumes that @p freq >= @p 1000000. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] usec number of microseconds + * @return The number of cycles. + * + * @api + */ +#define US2RTC(freq, usec) (rtcnt_t)((((freq) + 999999UL) / 1000000UL) * (usec)) + +/** + * @brief Realtime counter cycles to seconds. + * @details Converts from realtime counter cycles number to seconds. + * @note The result is rounded up to the next second boundary. + * @note The macro assumes that @p freq >= @p 1. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] n number of cycles + * @return The number of seconds. + * + * @api + */ +#define RTC2S(freq, n) ((((n) - 1UL) / (freq)) + 1UL) + +/** + * @brief Realtime counter cycles to milliseconds. + * @details Converts from realtime counter cycles number to milliseconds. + * @note The result is rounded up to the next millisecond boundary. + * @note The macro assumes that @p freq >= @p 1000. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] n number of cycles + * @return The number of milliseconds. + * + * @api + */ +#define RTC2MS(freq, n) ((((n) - 1UL) / ((freq) / 1000UL)) + 1UL) + +/** + * @brief Realtime counter cycles to microseconds. + * @details Converts from realtime counter cycles number to microseconds. + * @note The result is rounded up to the next microsecond boundary. + * @note The macro assumes that @p freq >= @p 1000000. + * + * @param[in] freq clock frequency, in Hz, of the realtime counter + * @param[in] n number of cycles + * @return The number of microseconds. + * + * @api + */ +#define RTC2US(freq, n) ((((n) - 1UL) / ((freq) / 1000000UL)) + 1UL) +/** @} */ + +/** + * @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 Performs a context switch. + * @note Not a user function, it is meant to be invoked by the scheduler + * itself or from within the port layer. + * + * @param[in] ntp the thread to be switched in + * @param[in] otp the thread to be switched out + * + * @special + */ +#define chSysSwitch(ntp, otp) { \ + \ + _trace_switch(ntp, otp); \ + _stats_ctxswc(ntp, otp); \ + CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp); \ + port_switch(ntp, otp); \ +} + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern stkalign_t ch_idle_thread_wa[]; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void chSysInit(void); + bool chSysIntegrityCheckI(unsigned testmask); + void chSysTimerHandlerI(void); + syssts_t chSysGetStatusAndLockX(void); + void chSysRestoreStatusX(syssts_t sts); +#if PORT_SUPPORTS_RT == TRUE + bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end); + void chSysPolledDelayX(rtcnt_t cycles); +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @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 + */ +static inline void chSysDisable(void) { + + 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 + */ +static inline void chSysSuspend(void) { + + 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 + */ +static inline void chSysEnable(void) { + + _dbg_check_enable(); + port_enable(); +} + +/** + * @brief Enters the kernel lock state. + * + * @special + */ +static inline void chSysLock(void) { + + port_lock(); + _stats_start_measure_crit_thd(); + _dbg_check_lock(); +} + +/** + * @brief Leaves the kernel lock state. + * + * @special + */ +static inline void chSysUnlock(void) { + + _dbg_check_unlock(); + _stats_stop_measure_crit_thd(); + + /* The following condition can be triggered by the use of i-class functions + in a critical section not followed by a chSchRescheduleS(), this means + that the current thread has a lower priority than the next thread in + the ready list.*/ + chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) || + (ch.rlist.current->prio >= ch.rlist.queue.next->prio), + "priority order violation"); + + 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 + */ +static inline void chSysLockFromISR(void) { + + port_lock_from_isr(); + _stats_start_measure_crit_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 + */ +static inline void chSysUnlockFromISR(void) { + + _dbg_check_unlock_from_isr(); + _stats_stop_measure_crit_isr(); + port_unlock_from_isr(); +} + +/** + * @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 + */ +static inline 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 + */ +static inline void chSysUnconditionalUnlock(void) { + + if (!port_irq_enabled(port_get_irq_status())) { + chSysUnlock(); + } +} + +#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__) +/** + * @brief Returns a pointer to the idle thread. + * @pre In order to use this function the option @p CH_CFG_NO_IDLE_THREAD + * must be disabled. + * @note The reference counter of the idle thread is not incremented but + * it is not strictly required being the idle thread a static + * object. + * + * @return Pointer to the idle thread. + * + * @xclass + */ +static inline thread_t *chSysGetIdleThreadX(void) { + + return ch.rlist.queue.prev; +} +#endif /* CH_CFG_NO_IDLE_THREAD == FALSE */ + +#endif /* CHSYS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chsystypes.h b/ChibiOS_20.3.2/os/rt/include/chsystypes.h new file mode 100644 index 0000000..7ca9159 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chsystypes.h @@ -0,0 +1,130 @@ +/* + 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 rt/include/chsystypes.h + * @brief System types header. + * + * @addtogroup scheduler + * @{ + */ + +#ifndef CHSYSTYPES_H +#define CHSYSTYPES_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @extends threads_queue_t + * + * @brief Type of a thread structure. + */ +typedef struct ch_thread thread_t; + +/** + * @brief Type of a thread reference. + */ +typedef thread_t * thread_reference_t; + +/** + * @brief Type of a generic threads single link list, it works like a stack. + */ +typedef struct ch_threads_list threads_list_t; + +/** + * @extends threads_list_t + * + * @brief Type of a generic threads bidirectional linked list header and element. + */ +typedef struct ch_threads_queue threads_queue_t; + +/** + * @extends threads_queue_t + * + * @brief Type of a ready list header. + */ +typedef struct ch_ready_list ready_list_t; + +/** + * @brief Type of a Virtual Timer callback function. + */ +typedef void (*vtfunc_t)(void *p); + +/** + * @brief Type of a Virtual Timer structure. + */ +typedef struct ch_virtual_timer virtual_timer_t; + +/** + * @brief Type of virtual timers list header. + */ +typedef struct ch_virtual_timers_list virtual_timers_list_t; + +/** + * @brief Type of a system debug structure. + */ +typedef struct ch_system_debug system_debug_t; + +/** + * @brief Type of system data structure. + */ +typedef struct ch_system ch_system_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @brief Utility to make the parameter a quoted string. + */ +#define __CH_STRINGIFY(a) #a + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHSYSTYPES_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chthreads.h b/ChibiOS_20.3.2/os/rt/include/chthreads.h new file mode 100644 index 0000000..74f8952 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chthreads.h @@ -0,0 +1,440 @@ +/* + 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 rt/include/chthreads.h + * @brief Threads module macros and structures. + * + * @addtogroup threads + * @{ + */ + +#ifndef CHTHREADS_H +#define CHTHREADS_H + +/*lint -sem(chThdExit, r_no) -sem(chThdExitS, r_no)*/ + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Thread function. + */ +typedef void (*tfunc_t)(void *p); + +/** + * @brief Type of a thread descriptor. + */ +typedef struct { + /** + * @brief Thread name. + */ + const char *name; + /** + * @brief Pointer to the working area base. + */ + stkalign_t *wbase; + /** + * @brief End of the working area. + */ + stkalign_t *wend; + /** + * @brief Thread priority. + */ + tprio_t prio; + /** + * @brief Thread function pointer. + */ + tfunc_t funcp; + /** + * @brief Thread argument. + */ + void *arg; +} thread_descriptor_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @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) {(thread_t *)&name, (thread_t *)&name} + +/** + * @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 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(sizeof(thread_t) + 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 Base of a working area casted to the correct type. + * + * @param[in] s name of the working area + */ +#define THD_WORKING_AREA_BASE(s) ((stkalign_t *)(s)) + +/** + * @brief End of a working area casted to the correct type. + * + * @param[in] s name of the working area + */ +#define THD_WORKING_AREA_END(s) (THD_WORKING_AREA_BASE(s) + \ + (sizeof (s) / 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 Macro Functions + * @{ + */ +/** + * @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 tick clock. + * @note The maximum specifiable value is implementation dependent. + * @note Use of this macro for large values is not secure because + * integer overflows, make sure your value can be correctly + * converted. + * + * @param[in] sec time in seconds, must be different from zero + * + * @api + */ +#define chThdSleepSeconds(sec) chThdSleep(TIME_S2I(sec)) + +/** + * @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 tick clock. + * @note The maximum specifiable value is implementation dependent. + * @note Use of this macro for large values is not secure because + * integer overflows, make sure your value can be correctly + * converted. + * + * @param[in] msec time in milliseconds, must be different from zero + * + * @api + */ +#define chThdSleepMilliseconds(msec) chThdSleep(TIME_MS2I(msec)) + +/** + * @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 tick clock. + * @note The maximum specifiable value is implementation dependent. + * @note Use of this macro for large values is not secure because + * integer overflows, make sure your value can be correctly + * converted. + * + * @param[in] usec time in microseconds, must be different from zero + * + * @api + */ +#define chThdSleepMicroseconds(usec) chThdSleep(TIME_US2I(usec)) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio); +#if CH_DBG_FILL_THREADS == TRUE + void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v); +#endif + thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp); + thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp); + thread_t *chThdCreateI(const thread_descriptor_t *tdp); + thread_t *chThdCreate(const thread_descriptor_t *tdp); + thread_t *chThdCreateStatic(void *wsp, size_t size, + tprio_t prio, tfunc_t pf, void *arg); + thread_t *chThdStart(thread_t *tp); +#if CH_CFG_USE_REGISTRY == TRUE + thread_t *chThdAddRef(thread_t *tp); + void chThdRelease(thread_t *tp); +#endif + void chThdExit(msg_t msg); + void chThdExitS(msg_t msg); +#if CH_CFG_USE_WAITEXIT == TRUE + msg_t chThdWait(thread_t *tp); +#endif + tprio_t chThdSetPriority(tprio_t newprio); + void chThdTerminate(thread_t *tp); + msg_t chThdSuspendS(thread_reference_t *trp); + msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout); + void chThdResumeI(thread_reference_t *trp, msg_t msg); + void chThdResumeS(thread_reference_t *trp, msg_t msg); + void chThdResume(thread_reference_t *trp, msg_t msg); + msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout); + void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg); + void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg); + void chThdSleep(sysinterval_t time); + void chThdSleepUntil(systime_t time); + systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next); + void chThdYield(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + + /** + * @brief Returns a pointer to the current @p thread_t. + * + * @return A pointer to the current thread. + * + * @xclass + */ +static inline thread_t *chThdGetSelfX(void) { + + return ch.rlist.current; +} + +/** + * @brief Returns the current thread priority. + * @note Can be invoked in any context. + * + * @return The current thread priority. + * + * @xclass + */ +static inline tprio_t chThdGetPriorityX(void) { + + return chThdGetSelfX()->prio; +} + +/** + * @brief Returns the number of ticks consumed by the specified thread. + * @note This function is only available when the + * @p CH_DBG_THREADS_PROFILING configuration option is enabled. + * + * @param[in] tp pointer to the thread + * @return The number of consumed system ticks. + * + * @xclass + */ +#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__) +static inline systime_t chThdGetTicksX(thread_t *tp) { + + return tp->time; +} +#endif + +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \ + defined(__DOXYGEN__) +/** + * @brief Returns the working area base of the specified thread. + * + * @param[in] tp pointer to the thread + * @return The working area base pointer. + * + * @xclass + */ +static inline stkalign_t *chThdGetWorkingAreaX(thread_t *tp) { + + return tp->wabase; +} +#endif /* CH_DBG_ENABLE_STACK_CHECK == TRUE */ + +/** + * @brief Verifies if the specified thread is in the @p CH_STATE_FINAL state. + * + * @param[in] tp pointer to the thread + * @retval true thread terminated. + * @retval false thread not terminated. + * + * @xclass + */ +static inline bool chThdTerminatedX(thread_t *tp) { + + return (bool)(tp->state == CH_STATE_FINAL); +} + +/** + * @brief Verifies if the current thread has a termination request pending. + * + * @retval true termination request pending. + * @retval false termination request not pending. + * + * @xclass + */ +static inline bool chThdShouldTerminateX(void) { + + return (bool)((chThdGetSelfX()->flags & CH_FLAG_TERMINATE) != (tmode_t)0); +} + +/** + * @brief Resumes a thread created with @p chThdCreateI(). + * + * @param[in] tp pointer to the thread + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @iclass + */ +static inline thread_t *chThdStartI(thread_t *tp) { + + chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state"); + + return chSchReadyI(tp); +} + +/** + * @brief Suspends the invoking thread for the specified number of ticks. + * + * @param[in] ticks the delay in system ticks, the special values are + * handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * + * @sclass + */ +static inline void chThdSleepS(sysinterval_t ticks) { + + chDbgCheck(ticks != TIME_IMMEDIATE); + + (void) chSchGoSleepTimeoutS(CH_STATE_SLEEPING, ticks); +} + +/** + * @brief Initializes a threads queue object. + * + * @param[out] tqp pointer to the threads queue object + * + * @init + */ +static inline void chThdQueueObjectInit(threads_queue_t *tqp) { + + queue_init(tqp); +} + +/** + * @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 + */ +static inline bool chThdQueueIsEmptyI(threads_queue_t *tqp) { + + chDbgCheckClassI(); + + return queue_isempty(tqp); +} + +/** + * @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 + */ +static inline void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) { + thread_t *tp; + + chDbgAssert(queue_notempty(tqp), "empty queue"); + + tp = queue_fifo_remove(tqp); + + chDbgAssert(tp->state == CH_STATE_QUEUED, "invalid state"); + + tp->u.rdymsg = msg; + (void) chSchReadyI(tp); +} + +#endif /* CHTHREADS_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chtime.h b/ChibiOS_20.3.2/os/rt/include/chtime.h new file mode 100644 index 0000000..c6c1de8 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chtime.h @@ -0,0 +1,492 @@ +/* + 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 rt/include/chtime.h + * @brief Time and intervals macros and structures. + * + * @addtogroup time_intervals + * @details This module is responsible for handling of system time and time + * intervals. + * @{ + */ + +#ifndef CHTIME_H +#define CHTIME_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @name Special time constants + * @{ + */ +/** + * @brief Zero interval 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)0) + +/** + * @brief Infinite interval specification for all functions with a timeout + * specification. + * @note Not all functions accept @p TIME_INFINITE as timeout parameter, + * see the specific function documentation. + */ +#define TIME_INFINITE ((sysinterval_t)-1) + +/** + * @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) +/** @} */ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32) && \ + (CH_CFG_ST_RESOLUTION != 64) +#error "invalid CH_CFG_ST_RESOLUTION specified, must be 16, 32 or 64" +#endif + +#if CH_CFG_ST_FREQUENCY < 10 +#error "invalid CH_CFG_ST_FREQUENCY specified, must be >= 10" +#endif + +#if (CH_CFG_INTERVALS_SIZE != 16) && (CH_CFG_INTERVALS_SIZE != 32) && \ + (CH_CFG_INTERVALS_SIZE != 64) +#error "invalid CH_CFG_INTERVALS_SIZE specified, must be 16, 32 or 64" +#endif + +#if (CH_CFG_TIME_TYPES_SIZE != 16) && (CH_CFG_TIME_TYPES_SIZE != 32) +#error "invalid CH_CFG_TIME_TYPES_SIZE specified, must be 16 or 32" +#endif + +#if CH_CFG_INTERVALS_SIZE < CH_CFG_ST_RESOLUTION +#error "CH_CFG_INTERVALS_SIZE must be >= CH_CFG_ST_RESOLUTION" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of system time. + * @note It is selectable in configuration between 16, 32 or 64 bits. + */ +#if (CH_CFG_ST_RESOLUTION == 64) || defined(__DOXYGEN__) +typedef uint64_t systime_t; +#elif CH_CFG_ST_RESOLUTION == 32 +typedef uint32_t systime_t; +#elif CH_CFG_ST_RESOLUTION == 16 +typedef uint16_t systime_t; +#endif + +/** + * @brief Type of time interval. + * @note It is selectable in configuration between 16, 32 or 64 bits. + */ +#if (CH_CFG_INTERVALS_SIZE == 64) || defined(__DOXYGEN__) +typedef uint64_t sysinterval_t; +#elif CH_CFG_INTERVALS_SIZE == 32 +typedef uint32_t sysinterval_t; +#elif CH_CFG_INTERVALS_SIZE == 16 +typedef uint16_t sysinterval_t; +#endif + +#if (CH_CFG_TIME_TYPES_SIZE == 32) || defined(__DOXYGEN__) +/** + * @brief Type of seconds. + * @note It is selectable in configuration between 16 or 32 bits. + */ +typedef uint32_t time_secs_t; + +/** + * @brief Type of milliseconds. + * @note It is selectable in configuration between 16 or 32 bits. + */ +typedef uint32_t time_msecs_t; + +/** + * @brief Type of microseconds. + * @note It is selectable in configuration between 16 or 32 bits. + */ +typedef uint32_t time_usecs_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 time_secs_t; +typedef uint16_t time_msecs_t; +typedef uint16_t time_usecs_t; +typedef uint32_t time_conv_t; +#endif + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Fast 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) +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/* + * Virtual Timers APIs. + */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @name Secure 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. + * + * @param[in] secs number of seconds + * @return The number of ticks. + * + * @special + */ +static inline sysinterval_t chTimeS2I(time_secs_t secs) { + time_conv_t ticks; + + ticks = (time_conv_t)secs * (time_conv_t)CH_CFG_ST_FREQUENCY; + + chDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, + "conversion overflow"); + + return (sysinterval_t)ticks; +} + +/** + * @brief Milliseconds to time interval. + * @details Converts from milliseconds to system ticks number. + * @note The result is rounded upward to the next tick boundary. + * + * @param[in] msec number of milliseconds + * @return The number of ticks. + * + * @special + */ +static inline sysinterval_t chTimeMS2I(time_msecs_t msec) { + time_conv_t ticks; + + ticks = (((time_conv_t)msec * (time_conv_t)CH_CFG_ST_FREQUENCY) + + (time_conv_t)999) / (time_conv_t)1000; + + chDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, + "conversion overflow"); + + return (sysinterval_t)ticks; +} + +/** + * @brief Microseconds to time interval. + * @details Converts from microseconds to system ticks number. + * @note The result is rounded upward to the next tick boundary. + * + * @param[in] usec number of microseconds + * @return The number of ticks. + * + * @special + */ +static inline sysinterval_t chTimeUS2I(time_usecs_t usec) { + time_conv_t ticks; + + ticks = (((time_conv_t)usec * (time_conv_t)CH_CFG_ST_FREQUENCY) + + (time_conv_t)999999) / (time_conv_t)1000000; + + chDbgAssert(ticks <= (time_conv_t)TIME_MAX_INTERVAL, + "conversion overflow"); + + return (sysinterval_t)ticks; +} + +/** + * @brief Time interval to seconds. + * @details Converts from system interval to seconds. + * @note The result is rounded up to the next second boundary. + * + * @param[in] interval interval in ticks + * @return The number of seconds. + * + * @special + */ +static inline time_secs_t chTimeI2S(sysinterval_t interval) { + time_conv_t secs; + + secs = ((time_conv_t)interval + + (time_conv_t)CH_CFG_ST_FREQUENCY - + (time_conv_t)1) / (time_conv_t)CH_CFG_ST_FREQUENCY; + + chDbgAssert(secs < (time_conv_t)((time_secs_t)-1), + "conversion overflow"); + + return (time_secs_t)secs; +} + +/** + * @brief Time interval to milliseconds. + * @details Converts from system interval to milliseconds. + * @note The result is rounded up to the next millisecond boundary. + * + * @param[in] interval interval in ticks + * @return The number of milliseconds. + * + * @special + */ +static inline time_msecs_t chTimeI2MS(sysinterval_t interval) { + time_conv_t msecs; + + msecs = (((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; + + chDbgAssert(msecs < (time_conv_t)((time_msecs_t)-1), + "conversion overflow"); + + return (time_msecs_t)msecs; +} + +/** + * @brief Time interval to microseconds. + * @details Converts from system interval to microseconds. + * @note The result is rounded up to the next microsecond boundary. + * + * @param[in] interval interval in ticks + * @return The number of microseconds. + * + * @special + */ +static inline time_usecs_t chTimeI2US(sysinterval_t interval) { + time_conv_t usecs; + + usecs = (((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; + + chDbgAssert(usecs <= (time_conv_t)((time_usecs_t)-1), + "conversion overflow"); + + return (time_usecs_t)usecs; +} + +/** + * @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 + */ +static inline systime_t chTimeAddX(systime_t systime, + sysinterval_t interval) { + +#if CH_CFG_ST_RESOLUTION != CH_CFG_INTERVALS_SIZE + chDbgCheck(interval <= (sysinterval_t)TIME_MAX_SYSTIME); +#endif + + return 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 + */ +static inline sysinterval_t chTimeDiffX(systime_t start, systime_t end) { + + /*lint -save -e9033 [10.8] This cast is required by the operation, it is + known that the destination type can be wider.*/ + return (sysinterval_t)((systime_t)(end - start)); + /*lint -restore*/ +} + +/** + * @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 + */ +static inline 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)); +} + +/** @} */ + +#endif /* CHTIME_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chtm.h b/ChibiOS_20.3.2/os/rt/include/chtm.h new file mode 100644 index 0000000..f068251 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chtm.h @@ -0,0 +1,109 @@ +/* + 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 rt/include/chtm.h + * @brief Time Measurement module macros and structures. + * + * @addtogroup time_measurement + * @{ + */ + +#ifndef CHTM_H +#define CHTM_H + +#if (CH_CFG_USE_TM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if PORT_SUPPORTS_RT == FALSE +#error "CH_CFG_USE_TM requires PORT_SUPPORTS_RT" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a time measurement calibration data. + */ +typedef struct { + /** + * @brief Measurement calibration value. + */ + rtcnt_t offset; +} tm_calibration_t; + +/** + * @brief Type of a Time Measurement object. + * @note The maximum measurable time period depends on the implementation + * of the realtime counter and its clock frequency. + * @note The measurement is not 100% cycle-accurate, it can be in excess + * of few cycles depending on the compiler and target architecture. + * @note Interrupts can affect measurement if the measurement is performed + * with interrupts enabled. + */ +typedef struct { + rtcnt_t best; /**< @brief Best measurement. */ + rtcnt_t worst; /**< @brief Worst measurement. */ + rtcnt_t last; /**< @brief Last measurement. */ + ucnt_t n; /**< @brief Number of measurements. */ + rttime_t cumulative; /**< @brief Cumulative measurement. */ +} time_measurement_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void _tm_init(void); + void chTMObjectInit(time_measurement_t *tmp); + NOINLINE void chTMStartMeasurementX(time_measurement_t *tmp); + NOINLINE void chTMStopMeasurementX(time_measurement_t *tmp); + NOINLINE void chTMChainMeasurementToX(time_measurement_t *tmp1, + time_measurement_t *tmp2); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CH_CFG_USE_TM == TRUE */ + +#endif /* CHTM_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chtrace.h b/ChibiOS_20.3.2/os/rt/include/chtrace.h new file mode 100644 index 0000000..c0a58ac --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chtrace.h @@ -0,0 +1,256 @@ +/* + 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 rt/include/chtrace.h + * @brief Tracer macros and structures. + * + * @addtogroup trace + * @{ + */ + +#ifndef CHTRACE_H +#define CHTRACE_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/** + * @name Trace record types + * @{ + */ +#define CH_TRACE_TYPE_UNUSED 0U +#define CH_TRACE_TYPE_SWITCH 1U +#define CH_TRACE_TYPE_ISR_ENTER 2U +#define CH_TRACE_TYPE_ISR_LEAVE 3U +#define CH_TRACE_TYPE_HALT 4U +#define CH_TRACE_TYPE_USER 5U +/** @} */ + +/** + * @name Events to trace + * @{ + */ +#define CH_DBG_TRACE_MASK_DISABLED 255U +#define CH_DBG_TRACE_MASK_NONE 0U +#define CH_DBG_TRACE_MASK_SWITCH 1U +#define CH_DBG_TRACE_MASK_ISR 2U +#define CH_DBG_TRACE_MASK_HALT 4U +#define CH_DBG_TRACE_MASK_USER 8U +#define CH_DBG_TRACE_MASK_SLOW (CH_DBG_TRACE_MASK_SWITCH | \ + CH_DBG_TRACE_MASK_HALT | \ + CH_DBG_TRACE_MASK_USER) +#define CH_DBG_TRACE_MASK_ALL (CH_DBG_TRACE_MASK_SWITCH | \ + CH_DBG_TRACE_MASK_ISR | \ + CH_DBG_TRACE_MASK_HALT | \ + CH_DBG_TRACE_MASK_USER) +/** @} */ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Debug related settings + * @{ + */ +/** + * @brief Trace buffer entries. + */ +#if !defined(CH_DBG_TRACE_MASK) || defined(__DOXYGEN__) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) || defined(__DOXYGEN__) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) +/*lint -save -e46 [6.1] An uint32_t is required.*/ +/** + * @brief Trace buffer record. + */ +typedef struct { + /** + * @brief Record type. + */ + uint32_t type:3; + /** + * @brief Switched out thread state. + */ + uint32_t state:5; + /** + * @brief Accurate time stamp. + * @note This field only available if the post supports + * @p PORT_SUPPORTS_RT else it is set to zero. + */ + uint32_t rtstamp:24; + /** + * @brief System time stamp of the switch event. + */ + systime_t time; + union { + /** + * @brief Structure representing a context switch. + */ + struct { + /** + * @brief Switched in thread. + */ + thread_t *ntp; + /** + * @brief Object where going to sleep. + */ + void *wtobjp; + } sw; + /** + * @brief Structure representing an ISR enter. + */ + struct { + /** + * @brief ISR function name taken using @p __func__. + */ + const char *name; + } isr; + /** + * @brief Structure representing an halt. + */ + struct { + /** + * @brief Halt error string. + */ + const char *reason; + } halt; + /** + * @brief User trace structure. + */ + struct { + /** + * @brief Trace user parameter 1. + */ + void *up1; + /** + * @brief Trace user parameter 2. + */ + void *up2; + } user; + } u; +} ch_trace_event_t; +/*lint -restore*/ + +/** + * @brief Trace buffer header. + */ +typedef struct { + /** + * @brief Suspended trace sources mask. + */ + uint16_t suspended; + /** + * @brief Trace buffer size (entries). + */ + uint16_t size; + /** + * @brief Pointer to the buffer front. + */ + ch_trace_event_t *ptr; + /** + * @brief Ring buffer. + */ + ch_trace_event_t buffer[CH_DBG_TRACE_BUFFER_SIZE]; +} ch_trace_buffer_t; +#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED */ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/* When a trace feature is disabled the associated functions are replaced by + an empty macro. Note that the macros can be externally redefined in + order to interface 3rd parties tracing tools.*/ +#if CH_DBG_TRACE_MASK == CH_DBG_TRACE_MASK_DISABLED +#if !defined(_trace_init) +#define _trace_init() +#endif +#if !defined(_trace_switch) +#define _trace_switch(ntp, otp) +#endif +#if !defined(_trace_isr_enter) +#define _trace_isr_enter(isr) +#endif +#if !defined(_trace_isr_leave) +#define _trace_isr_leave(isr) +#endif +#if !defined(_trace_halt) +#define _trace_halt(reason) +#endif +#if !defined(chDbgWriteTraceI) +#define chDbgWriteTraceI(up1, up2) +#endif +#if !defined(chDbgWriteTrace) +#define chDbgWriteTrace(up1, up2) +#endif +#endif /* CH_DBG_TRACE_MASK == CH_DBG_TRACE_MASK_DISABLED */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif +#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) + void _trace_init(void); + void _trace_switch(thread_t *ntp, thread_t *otp); + void _trace_isr_enter(const char *isr); + void _trace_isr_leave(const char *isr); + void _trace_halt(const char *reason); + void chDbgWriteTraceI(void *up1, void *up2); + void chDbgWriteTrace(void *up1, void *up2); + void chDbgSuspendTraceI(uint16_t mask); + void chDbgSuspendTrace(uint16_t mask); + void chDbgResumeTraceI(uint16_t mask); + void chDbgResumeTrace(uint16_t mask); +#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED */ +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHTRACE_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/include/chvt.h b/ChibiOS_20.3.2/os/rt/include/chvt.h new file mode 100644 index 0000000..ed1c512 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/include/chvt.h @@ -0,0 +1,362 @@ +/* + 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 rt/include/chvt.h + * @brief Time and Virtual Timers module macros and structures. + * + * @addtogroup time + * @{ + */ + +#ifndef CHVT_H +#define CHVT_H + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#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_ST_TIMEDELTA > 0) && (CH_CFG_TIME_QUANTUM > 0) +#error "CH_CFG_TIME_QUANTUM not supported in tickless mode" +#endif + +#if (CH_CFG_ST_TIMEDELTA > 0) && (CH_DBG_THREADS_PROFILING == TRUE) +#error "CH_DBG_THREADS_PROFILING not supported in tickless mode" +#endif + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +/* + * Virtual Timers APIs. + */ +#ifdef __cplusplus +extern "C" { +#endif + void _vt_init(void); + void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par); + void chVTDoResetI(virtual_timer_t *vtp); + void chVTDoTickI(void); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes a @p virtual_timer_t object. + * @note Initializing a timer object is not strictly required because + * the function @p chVTSetI() initializes the object too. This + * function is only useful if you need to perform a @p chVTIsArmed() + * check before calling @p chVTSetI(). + * + * @param[out] vtp the @p virtual_timer_t structure pointer + * + * @init + */ +static inline void chVTObjectInit(virtual_timer_t *vtp) { + + vtp->func = NULL; +} + +/** + * @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 + */ +static inline systime_t chVTGetSystemTimeX(void) { + +#if CH_CFG_ST_TIMEDELTA == 0 + return ch.vtlist.systime; +#else /* CH_CFG_ST_TIMEDELTA > 0 */ + return port_timer_get_time(); +#endif /* CH_CFG_ST_TIMEDELTA > 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. + * + * @return The system time in ticks. + * + * @api + */ +static inline systime_t chVTGetSystemTime(void) { + systime_t systime; + + chSysLock(); + systime = chVTGetSystemTimeX(); + chSysUnlock(); + + return systime; +} + +/** + * @brief Returns the elapsed time since the specified start time. + * + * @param[in] start start time + * @return The elapsed time. + * + * @xclass + */ +static inline sysinterval_t chVTTimeElapsedSinceX(systime_t start) { + + return 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 + */ +static inline bool chVTIsSystemTimeWithinX(systime_t start, systime_t end) { + + return chTimeIsInRangeX(chVTGetSystemTimeX(), start, end); +} + +/** + * @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. + * + * @api + */ +static inline bool chVTIsSystemTimeWithin(systime_t start, systime_t end) { + + return chTimeIsInRangeX(chVTGetSystemTime(), start, end); +} + +/** + * @brief Returns the time interval until the next timer event. + * @note The return value is not perfectly accurate and can report values + * in excess of @p CH_CFG_ST_TIMEDELTA ticks. + * @note The interval returned by this function is only meaningful if + * more timers are not added to the list until the returned time. + * + * @param[out] timep pointer to a variable that will contain the time + * interval until the next timer elapses. This pointer + * can be @p NULL if the information is not required. + * @return The time, in ticks, until next time event. + * @retval false if the timers list is empty. + * @retval true if the timers list contains at least one timer. + * + * @iclass + */ +static inline bool chVTGetTimersStateI(sysinterval_t *timep) { + + chDbgCheckClassI(); + + if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) { + return false; + } + + if (timep != NULL) { +#if CH_CFG_ST_TIMEDELTA == 0 + *timep = ch.vtlist.next->delta; +#else + *timep = (ch.vtlist.next->delta + (sysinterval_t)CH_CFG_ST_TIMEDELTA) - + chTimeDiffX(ch.vtlist.lasttime, chVTGetSystemTimeX()); +#endif + } + + return true; +} + +/** + * @brief Returns @p true if the specified timer is armed. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @return true if the timer is armed. + * + * @iclass + */ +static inline bool chVTIsArmedI(const virtual_timer_t *vtp) { + + chDbgCheckClassI(); + + return (bool)(vtp->func != NULL); +} + +/** + * @brief Returns @p true if the specified timer is armed. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @return true if the timer is armed. + * + * @api + */ +static inline bool chVTIsArmed(const virtual_timer_t *vtp) { + bool b; + + chSysLock(); + b = chVTIsArmedI(vtp); + chSysUnlock(); + + return b; +} + +/** + * @brief Disables a Virtual Timer. + * @note The timer is first checked and disabled only if armed. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * + * @iclass + */ +static inline void chVTResetI(virtual_timer_t *vtp) { + + if (chVTIsArmedI(vtp)) { + chVTDoResetI(vtp); + } +} + +/** + * @brief Disables a Virtual Timer. + * @note The timer is first checked and disabled only if armed. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * + * @api + */ +static inline void chVTReset(virtual_timer_t *vtp) { + + chSysLock(); + chVTResetI(vtp); + chSysUnlock(); +} + +/** + * @brief Enables a virtual timer. + * @details If the virtual timer was already enabled then it is re-enabled + * using the new parameters. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @iclass + */ +static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + + chVTResetI(vtp); + chVTDoSetI(vtp, delay, vtfunc, par); +} + +/** + * @brief Enables a virtual timer. + * @details If the virtual timer was already enabled then it is re-enabled + * using the new parameters. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @api + */ +static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + + chSysLock(); + chVTSetI(vtp, delay, vtfunc, par); + chSysUnlock(); +} + +#endif /* CHVT_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/rt.mk b/ChibiOS_20.3.2/os/rt/rt.mk new file mode 100644 index 0000000..3294ce8 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/rt.mk @@ -0,0 +1,75 @@ +# List of all the ChibiOS/RT 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/rt/src/chsys.c \ + $(CHIBIOS)/os/rt/src/chdebug.c \ + $(CHIBIOS)/os/rt/src/chtrace.c \ + $(CHIBIOS)/os/rt/src/chvt.c \ + $(CHIBIOS)/os/rt/src/chschd.c \ + $(CHIBIOS)/os/rt/src/chthreads.c +ifneq ($(findstring CH_CFG_USE_TM TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chtm.c +endif +ifneq ($(findstring CH_DBG_STATISTICS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chstats.c +endif +ifneq ($(findstring CH_CFG_USE_REGISTRY TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chregistry.c +endif +ifneq ($(findstring CH_CFG_USE_SEMAPHORES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chsem.c +endif +ifneq ($(findstring CH_CFG_USE_MUTEXES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chmtx.c +endif +ifneq ($(findstring CH_CFG_USE_CONDVARS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chcond.c +endif +ifneq ($(findstring CH_CFG_USE_EVENTS TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chevents.c +endif +ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chmsg.c +endif +ifneq ($(findstring CH_CFG_USE_DYNAMIC TRUE,$(CHCONF)),) +KERNSRC += $(CHIBIOS)/os/rt/src/chdynamic.c +endif +else +KERNSRC := $(CHIBIOS)/os/rt/src/chsys.c \ + $(CHIBIOS)/os/rt/src/chdebug.c \ + $(CHIBIOS)/os/rt/src/chtrace.c \ + $(CHIBIOS)/os/rt/src/chvt.c \ + $(CHIBIOS)/os/rt/src/chschd.c \ + $(CHIBIOS)/os/rt/src/chthreads.c \ + $(CHIBIOS)/os/rt/src/chtm.c \ + $(CHIBIOS)/os/rt/src/chstats.c \ + $(CHIBIOS)/os/rt/src/chregistry.c \ + $(CHIBIOS)/os/rt/src/chsem.c \ + $(CHIBIOS)/os/rt/src/chmtx.c \ + $(CHIBIOS)/os/rt/src/chcond.c \ + $(CHIBIOS)/os/rt/src/chevents.c \ + $(CHIBIOS)/os/rt/src/chmsg.c \ + $(CHIBIOS)/os/rt/src/chdynamic.c +endif + +# Required include directories +KERNINC := $(CHIBIOS)/os/rt/include + +# Shared variables +ALLCSRC += $(KERNSRC) +ALLINC += $(KERNINC) + +# OS Library +include $(CHIBIOS)/os/oslib/oslib.mk diff --git a/ChibiOS_20.3.2/os/rt/src/chcond.c b/ChibiOS_20.3.2/os/rt/src/chcond.c new file mode 100644 index 0000000..bd653c3 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chcond.c @@ -0,0 +1,321 @@ +/* + 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 . +*/ +/* + Concepts and parts of this file have been contributed by Leon Woestenberg. + */ + +/** + * @file rt/src/chcond.c + * @brief Condition Variables code. + * + * @addtogroup condvars + * @details This module implements the Condition Variables mechanism. Condition + * variables are an extensions to the mutex subsystem and cannot + * work alone. + *

Operation mode

+ * The condition variable is a synchronization object meant to be + * used inside a zone protected by a mutex. Mutexes and condition + * variables together can implement a Monitor construct. + * @pre In order to use the condition variable APIs the @p CH_CFG_USE_CONDVARS + * option must be enabled in @p chconf.h. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_CONDVARS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes s @p condition_variable_t structure. + * + * @param[out] cp pointer to a @p condition_variable_t structure + * + * @init + */ +void chCondObjectInit(condition_variable_t *cp) { + + chDbgCheck(cp != NULL); + + queue_init(&cp->queue); +} + +/** + * @brief Signals one thread that is waiting on the condition variable. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * + * @api + */ +void chCondSignal(condition_variable_t *cp) { + + chDbgCheck(cp != NULL); + + chSysLock(); + if (queue_notempty(&cp->queue)) { + chSchWakeupS(queue_fifo_remove(&cp->queue), MSG_OK); + } + chSysUnlock(); +} + +/** + * @brief Signals one thread that is waiting on the condition variable. + * @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] cp pointer to the @p condition_variable_t structure + * + * @iclass + */ +void chCondSignalI(condition_variable_t *cp) { + + chDbgCheckClassI(); + chDbgCheck(cp != NULL); + + if (queue_notempty(&cp->queue)) { + thread_t *tp = queue_fifo_remove(&cp->queue); + tp->u.rdymsg = MSG_OK; + (void) chSchReadyI(tp); + } +} + +/** + * @brief Signals all threads that are waiting on the condition variable. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * + * @api + */ +void chCondBroadcast(condition_variable_t *cp) { + + chSysLock(); + chCondBroadcastI(cp); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Signals all threads that are waiting on the condition variable. + * @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] cp pointer to the @p condition_variable_t structure + * + * @iclass + */ +void chCondBroadcastI(condition_variable_t *cp) { + + chDbgCheckClassI(); + chDbgCheck(cp != NULL); + + /* Empties the condition variable queue and inserts all the threads into the + ready list in FIFO order. The wakeup message is set to @p MSG_RESET in + order to make a chCondBroadcast() detectable from a chCondSignal().*/ + while (queue_notempty(&cp->queue)) { + chSchReadyI(queue_fifo_remove(&cp->queue))->u.rdymsg = MSG_RESET; + } +} + +/** + * @brief Waits on the condition variable releasing the mutex lock. + * @details Releases the currently owned mutex, waits on the condition + * variable, and finally acquires the mutex again. All the sequence + * is performed atomically. + * @pre The invoking thread must have at least one owned mutex. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * @return A message specifying how the invoking thread has been + * released from the condition variable. + * @retval MSG_OK if the condition variable has been signaled using + * @p chCondSignal(). + * @retval MSG_RESET if the condition variable has been signaled using + * @p chCondBroadcast(). + * + * @api + */ +msg_t chCondWait(condition_variable_t *cp) { + msg_t msg; + + chSysLock(); + msg = chCondWaitS(cp); + chSysUnlock(); + return msg; +} + +/** + * @brief Waits on the condition variable releasing the mutex lock. + * @details Releases the currently owned mutex, waits on the condition + * variable, and finally acquires the mutex again. All the sequence + * is performed atomically. + * @pre The invoking thread must have at least one owned mutex. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * @return A message specifying how the invoking thread has been + * released from the condition variable. + * @retval MSG_OK if the condition variable has been signaled using + * @p chCondSignal(). + * @retval MSG_RESET if the condition variable has been signaled using + * @p chCondBroadcast(). + * + * @sclass + */ +msg_t chCondWaitS(condition_variable_t *cp) { + thread_t *ctp = currp; + mutex_t *mp = chMtxGetNextMutexX(); + msg_t msg; + + chDbgCheckClassS(); + chDbgCheck(cp != NULL); + chDbgAssert(mp != NULL, "not owning a mutex"); + + /* Releasing "current" mutex.*/ + chMtxUnlockS(mp); + + /* Start waiting on the condition variable, on exit the mutex is taken + again.*/ + ctp->u.wtobjp = cp; + queue_prio_insert(ctp, &cp->queue); + chSchGoSleepS(CH_STATE_WTCOND); + msg = ctp->u.rdymsg; + chMtxLockS(mp); + + return msg; +} + +#if (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Waits on the condition variable releasing the mutex lock. + * @details Releases the currently owned mutex, waits on the condition + * variable, and finally acquires the mutex again. All the sequence + * is performed atomically. + * @pre The invoking thread must have at least one owned mutex. + * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled + * in order to use this function. + * @post Exiting the function because a timeout does not re-acquire the + * mutex, the mutex ownership is lost. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * @param[in] timeout the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE no timeout. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @return A message specifying how the invoking thread has been + * released from the condition variable. + * @retval MSG_OK if the condition variable has been signaled using + * @p chCondSignal(). + * @retval MSG_RESET if the condition variable has been signaled using + * @p chCondBroadcast(). + * @retval MSG_TIMEOUT if the condition variable has not been signaled within + * the specified timeout. + * + * @api + */ +msg_t chCondWaitTimeout(condition_variable_t *cp, sysinterval_t timeout) { + msg_t msg; + + chSysLock(); + msg = chCondWaitTimeoutS(cp, timeout); + chSysUnlock(); + + return msg; +} + +/** + * @brief Waits on the condition variable releasing the mutex lock. + * @details Releases the currently owned mutex, waits on the condition + * variable, and finally acquires the mutex again. All the sequence + * is performed atomically. + * @pre The invoking thread must have at least one owned mutex. + * @pre The configuration option @p CH_CFG_USE_CONDVARS_TIMEOUT must be enabled + * in order to use this function. + * @post Exiting the function because a timeout does not re-acquire the + * mutex, the mutex ownership is lost. + * + * @param[in] cp pointer to the @p condition_variable_t structure + * @param[in] timeout the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE no timeout. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @return A message specifying how the invoking thread has been + * released from the condition variable. + * @retval MSG_OK if the condition variable has been signaled using + * @p chCondSignal(). + * @retval MSG_RESET if the condition variable has been signaled using + * @p chCondBroadcast(). + * @retval MSG_TIMEOUT if the condition variable has not been signaled within + * the specified timeout. + * + * @sclass + */ +msg_t chCondWaitTimeoutS(condition_variable_t *cp, sysinterval_t timeout) { + mutex_t *mp = chMtxGetNextMutexX(); + msg_t msg; + + chDbgCheckClassS(); + chDbgCheck((cp != NULL) && (timeout != TIME_IMMEDIATE)); + chDbgAssert(mp != NULL, "not owning a mutex"); + + /* Releasing "current" mutex.*/ + chMtxUnlockS(mp); + + /* Start waiting on the condition variable, on exit the mutex is taken + again.*/ + currp->u.wtobjp = cp; + queue_prio_insert(currp, &cp->queue); + msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, timeout); + if (msg != MSG_TIMEOUT) { + chMtxLockS(mp); + } + + return msg; +} +#endif /* CH_CFG_USE_CONDVARS_TIMEOUT == TRUE */ + +#endif /* CH_CFG_USE_CONDVARS == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chdebug.c b/ChibiOS_20.3.2/os/rt/src/chdebug.c new file mode 100644 index 0000000..d73950c --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chdebug.c @@ -0,0 +1,257 @@ +/* + 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 rt/src/chdebug.c + * @brief Debug support code. + * + * @addtogroup checks_assertions + * @details Debug APIs and services: + * - Runtime system state and call protocol check. The following + * panic messages can be generated: + * - SV#1, misplaced @p chSysDisable(). + * - Called from an ISR. + * - Called from a critical zone. + * . + * - SV#2, misplaced @p chSysSuspend() + * - Called from an ISR. + * - Called from a critical zone. + * . + * - SV#3, misplaced @p chSysEnable(). + * - Called from an ISR. + * - Called from a critical zone. + * . + * - SV#4, misplaced @p chSysLock(). + * - Called from an ISR. + * - Called from a critical zone. + * . + * - SV#5, misplaced @p chSysUnlock(). + * - Called from an ISR. + * - Not called from a critical zone. + * . + * - SV#6, misplaced @p chSysLockFromISR(). + * - Not called from an ISR. + * - Called from a critical zone. + * . + * - SV#7, misplaced @p chSysUnlockFromISR(). + * - Not called from an ISR. + * - Not called from a critical zone. + * . + * - SV#8, misplaced @p CH_IRQ_PROLOGUE(). + * - Not called at ISR begin. + * - Called from a critical zone. + * . + * - SV#9, misplaced @p CH_IRQ_EPILOGUE(). + * - @p CH_IRQ_PROLOGUE() missing. + * - Not called at ISR end. + * - Called from a critical zone. + * . + * - SV#10, misplaced I-class function. + * - I-class function not called from within a critical zone. + * . + * - SV#11, misplaced S-class function. + * - S-class function not called from within a critical zone. + * - Called from an ISR. + * . + * - Parameters check. + * - Kernel assertions. + * . + * @note Stack checks are not implemented in this module but in the port + * layer in an architecture-dependent way. + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__) +/** + * @brief Guard code for @p chSysDisable(). + * + * @notapi + */ +void _dbg_check_disable(void) { + + if ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#1"); + } +} + +/** + * @brief Guard code for @p chSysSuspend(). + * + * @notapi + */ +void _dbg_check_suspend(void) { + + if ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#2"); + } +} + +/** + * @brief Guard code for @p chSysEnable(). + * + * @notapi + */ +void _dbg_check_enable(void) { + + if ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#3"); + } +} + +/** + * @brief Guard code for @p chSysLock(). + * + * @notapi + */ +void _dbg_check_lock(void) { + + if ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#4"); + } + _dbg_enter_lock(); +} + +/** + * @brief Guard code for @p chSysUnlock(). + * + * @notapi + */ +void _dbg_check_unlock(void) { + + if ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.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 ((ch.dbg.isr_cnt <= (cnt_t)0) || (ch.dbg.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 ((ch.dbg.isr_cnt <= (cnt_t)0) || (ch.dbg.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 ((ch.dbg.isr_cnt < (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#8"); + } + ch.dbg.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 ((ch.dbg.isr_cnt <= (cnt_t)0) || (ch.dbg.lock_cnt != (cnt_t)0)) { + chSysHalt("SV#9"); + } + ch.dbg.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 ((ch.dbg.isr_cnt < (cnt_t)0) || (ch.dbg.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 ((ch.dbg.isr_cnt != (cnt_t)0) || (ch.dbg.lock_cnt <= (cnt_t)0)) { + chSysHalt("SV#11"); + } +} + +#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chdynamic.c b/ChibiOS_20.3.2/os/rt/src/chdynamic.c new file mode 100644 index 0000000..a11c219 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chdynamic.c @@ -0,0 +1,185 @@ +/* + 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 rt/src/chdynamic.c + * @brief Dynamic threads code. + * + * @addtogroup dynamic_threads + * @details Dynamic threads related APIs and services. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__) +/** + * @brief Creates a new thread allocating the memory from the heap. + * @pre The configuration options @p CH_CFG_USE_DYNAMIC and + * @p CH_CFG_USE_HEAP must be enabled in order to use this function. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * @note The memory allocated for the thread is not released automatically, + * it is responsibility of the creator thread to call @p chThdWait() + * and then release the allocated memory. + * + * @param[in] heapp heap from which allocate the memory or @p NULL for the + * default heap + * @param[in] size size of the working area to be allocated + * @param[in] name thread name + * @param[in] prio the priority level for the new thread + * @param[in] pf the thread function + * @param[in] arg an argument passed to the thread function. It can be + * @p NULL. + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * @retval NULL if the memory cannot be allocated. + * + * @api + */ +thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size, + const char *name, tprio_t prio, + tfunc_t pf, void *arg) { + thread_t *tp; + void *wsp; + + wsp = chHeapAllocAligned(heapp, size, PORT_WORKING_AREA_ALIGN); + if (wsp == NULL) { + return NULL; + } + + thread_descriptor_t td = { + name, + wsp, + (stkalign_t *)((uint8_t *)wsp + size), + prio, + pf, + arg + }; + +#if CH_DBG_FILL_THREADS == TRUE + _thread_memfill((uint8_t *)wsp, + (uint8_t *)wsp + size, + CH_DBG_STACK_FILL_VALUE); +#endif + + chSysLock(); + tp = chThdCreateSuspendedI(&td); + tp->flags = CH_FLAG_MODE_HEAP; + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + + return tp; +} +#endif /* CH_CFG_USE_HEAP == TRUE */ + +#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Creates a new thread allocating the memory from the specified + * memory pool. + * @pre The configuration options @p CH_CFG_USE_DYNAMIC and + * @p CH_CFG_USE_MEMPOOLS must be enabled in order to use this + * function. + * @pre The pool must be initialized to contain only objects with + * alignment @p PORT_WORKING_AREA_ALIGN. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * @note The memory allocated for the thread is not released automatically, + * it is responsibility of the creator thread to call @p chThdWait() + * and then release the allocated memory. + * + * @param[in] mp pointer to the memory pool object + * @param[in] name thread name + * @param[in] prio the priority level for the new thread + * @param[in] pf the thread function + * @param[in] arg an argument passed to the thread function. It can be + * @p NULL. + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * @retval NULL if the memory pool is empty. + * + * @api + */ +thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, const char *name, + tprio_t prio, tfunc_t pf, void *arg) { + thread_t *tp; + void *wsp; + + chDbgCheck(mp != NULL); + + wsp = chPoolAlloc(mp); + if (wsp == NULL) { + return NULL; + } + + thread_descriptor_t td = { + name, + wsp, + (stkalign_t *)((uint8_t *)wsp + mp->object_size), + prio, + pf, + arg + }; + +#if CH_DBG_FILL_THREADS == TRUE + _thread_memfill((uint8_t *)wsp, + (uint8_t *)wsp + mp->object_size, + CH_DBG_STACK_FILL_VALUE); +#endif + + chSysLock(); + tp = chThdCreateSuspendedI(&td); + tp->flags = CH_FLAG_MODE_MPOOL; + tp->mpool = mp; + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + + return tp; +} +#endif /* CH_CFG_USE_MEMPOOLS == TRUE */ + +#endif /* CH_CFG_USE_DYNAMIC == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chevents.c b/ChibiOS_20.3.2/os/rt/src/chevents.c new file mode 100644 index 0000000..9b84ce2 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chevents.c @@ -0,0 +1,603 @@ +/* + 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 . +*/ +/* + Concepts and parts of this file have been contributed by Scott (skute). + */ + +/** + * @file rt/src/chevents.c + * @brief Events code. + * + * @addtogroup events + * @details Event Flags, Event Sources and Event Listeners. + *

Operation mode

+ * Each thread has a mask of pending events inside its + * @p thread_t structure. + * Operations defined for events: + * - Wait, the invoking thread goes to sleep until a certain + * AND/OR combination of events are signaled. + * - Clear, a mask of events is cleared from the pending + * events, the cleared events mask is returned (only the + * events that were actually pending and then cleared). + * - Signal, an events mask is directly ORed to the mask of + * the signaled thread. + * - Broadcast, each thread registered on an Event Source is + * signaled with the events specified in its Event Listener. + * - Dispatch, an events mask is scanned and for each bit set + * to one an associated handler function is invoked. Bit masks are + * scanned from bit zero upward. + * . + * An Event Source is a special object that can be "broadcasted" by + * a thread or an interrupt service routine. Broadcasting an Event + * Source has the effect that all the threads registered on the + * Event Source will be signaled with an events mask.
+ * An unlimited number of Event Sources can exists in a system and + * each thread can be listening on an unlimited number of + * them. + * @pre In order to use the Events APIs the @p CH_CFG_USE_EVENTS option + * must be enabled in @p chconf.h. + * @post Enabling events requires 1-4 (depending on the architecture) + * extra bytes in the @p thread_t structure. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* 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 = currp; + 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 = currp->epending & events; + currp->epending &= ~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 events set to be ORed + * + * @api + */ +void chEvtSignal(thread_t *tp, eventmask_t events) { + + chDbgCheck(tp != NULL); + + 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 events set to be ORed + * + * @iclass + */ +void chEvtSignalI(thread_t *tp, eventmask_t events) { + + chDbgCheckClassI(); + chDbgCheck(tp != NULL); + + tp->epending |= events; + /* Test on the AND/OR conditions wait states.*/ + if (((tp->state == CH_STATE_WTOREVT) && + ((tp->epending & tp->u.ewmask) != (eventmask_t)0)) || + ((tp->state == CH_STATE_WTANDEVT) && + ((tp->epending & tp->u.ewmask) == tp->u.ewmask))) { + tp->u.rdymsg = MSG_OK; + (void) chSchReadyI(tp); + } +} + +/** + * @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++; + } +} + +#if (CH_CFG_OPTIMIZE_SPEED == TRUE) || \ + (CH_CFG_USE_EVENTS_TIMEOUT == FALSE) || \ + defined(__DOXYGEN__) +/** + * @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. + * + * @api + */ +eventmask_t chEvtWaitOne(eventmask_t events) { + thread_t *ctp = currp; + eventmask_t m; + + chSysLock(); + m = ctp->epending & events; + if (m == (eventmask_t)0) { + ctp->u.ewmask = events; + chSchGoSleepS(CH_STATE_WTOREVT); + m = ctp->epending & events; + } + m ^= m & (m - (eventmask_t)1); + ctp->epending &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for any of the specified events. + * @details The function waits for any event among those specified in + * @p events 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. + * + * @api + */ +eventmask_t chEvtWaitAny(eventmask_t events) { + thread_t *ctp = currp; + eventmask_t m; + + chSysLock(); + m = ctp->epending & events; + if (m == (eventmask_t)0) { + ctp->u.ewmask = events; + chSchGoSleepS(CH_STATE_WTOREVT); + m = ctp->epending & events; + } + ctp->epending &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for all the specified events. + * @details The function waits for all the events specified in @p events to + * become pending then the events are cleared and returned. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS requires all the events + * @return The mask of the served and cleared events. + * + * @api + */ +eventmask_t chEvtWaitAll(eventmask_t events) { + thread_t *ctp = currp; + + chSysLock(); + if ((ctp->epending & events) != events) { + ctp->u.ewmask = events; + chSchGoSleepS(CH_STATE_WTANDEVT); + } + ctp->epending &= ~events; + chSysUnlock(); + + return events; +} +#endif /* CH_CFG_OPTIMIZE_SPEED || !CH_CFG_USE_EVENTS_TIMEOUT */ + +#if (CH_CFG_USE_EVENTS_TIMEOUT == TRUE) || defined(__DOXYGEN__) +/** + * @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 = currp; + eventmask_t m; + + chSysLock(); + m = ctp->epending & events; + if (m == (eventmask_t)0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + return (eventmask_t)0; + } + ctp->u.ewmask = events; + if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + return (eventmask_t)0; + } + m = ctp->epending & events; + } + m ^= m & (m - (eventmask_t)1); + ctp->epending &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for any of the specified events. + * @details The function waits for any event among those specified in + * @p events 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 + * @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 events, sysinterval_t timeout) { + thread_t *ctp = currp; + eventmask_t m; + + chSysLock(); + m = ctp->epending & events; + if (m == (eventmask_t)0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + return (eventmask_t)0; + } + ctp->u.ewmask = events; + if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + return (eventmask_t)0; + } + m = ctp->epending & events; + } + ctp->epending &= ~m; + chSysUnlock(); + + return m; +} + +/** + * @brief Waits for all the specified events. + * @details The function waits for all the events specified in @p events to + * become pending then the events are cleared and returned. + * + * @param[in] events events that the function should wait + * for, @p ALL_EVENTS requires 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 events, sysinterval_t timeout) { + thread_t *ctp = currp; + + chSysLock(); + if ((ctp->epending & events) != events) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + return (eventmask_t)0; + } + ctp->u.ewmask = events; + if (chSchGoSleepTimeoutS(CH_STATE_WTANDEVT, timeout) < MSG_OK) { + chSysUnlock(); + return (eventmask_t)0; + } + } + ctp->epending &= ~events; + chSysUnlock(); + + return events; +} +#endif /* CH_CFG_USE_EVENTS_TIMEOUT == TRUE */ + +#endif /* CH_CFG_USE_EVENTS == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chmsg.c b/ChibiOS_20.3.2/os/rt/src/chmsg.c new file mode 100644 index 0000000..2003dd0 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chmsg.c @@ -0,0 +1,221 @@ +/* + 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 rt/src/chmsg.c + * @brief Messages code. + * + * @addtogroup messages + * @details Synchronous inter-thread messages APIs and services. + *

Operation Mode

+ * Synchronous messages are an easy to use and fast IPC mechanism, + * threads can both act as message servers and/or message clients, + * the mechanism allows data to be carried in both directions. Note + * that messages are not copied between the client and server threads + * but just a pointer passed so the exchange is very time + * efficient.
+ * Messages are scalar data types of type @p msg_t that are guaranteed + * to be size compatible with data pointers. Note that on some + * architectures function pointers can be larger that @p msg_t.
+ * Messages are usually processed in FIFO order but it is possible to + * process them in priority order by enabling the + * @p CH_CFG_USE_MESSAGES_PRIORITY option in @p chconf.h.
+ * @pre In order to use the message APIs the @p CH_CFG_USE_MESSAGES option + * must be enabled in @p chconf.h. + * @post Enabling messages requires 6-12 (depending on the architecture) + * extra bytes in the @p thread_t structure. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if CH_CFG_USE_MESSAGES_PRIORITY == TRUE +#define msg_insert(tp, qp) queue_prio_insert(tp, qp) +#else +#define msg_insert(tp, qp) queue_insert(tp, qp) +#endif + +/*===========================================================================*/ +/* 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 = currp; + + chDbgCheck(tp != NULL); + + chSysLock(); + ctp->u.sentmsg = msg; + msg_insert(ctp, &tp->msgqueue); + if (tp->state == CH_STATE_WTMSG) { + (void) chSchReadyI(tp); + } + chSchGoSleepS(CH_STATE_SNDMSGQ); + msg = ctp->u.rdymsg; + 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. + * + * @sclass + */ +thread_t *chMsgWaitS(void) { + thread_t *tp; + + chDbgCheckClassS(); + + if (!chMsgIsPendingI(currp)) { + chSchGoSleepS(CH_STATE_WTMSG); + } + tp = queue_fifo_remove(&currp->msgqueue); + tp->state = CH_STATE_SNDMSG; + + 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(); + + if (!chMsgIsPendingI(currp)) { + if (chSchGoSleepTimeoutS(CH_STATE_WTMSG, timeout) != MSG_OK) { + return NULL; + } + } + tp = queue_fifo_remove(&currp->msgqueue); + tp->state = CH_STATE_SNDMSG; + + return tp; +} + +/** + * @brief Poll to check for an incoming message. + * @post If a message is available 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 Result of the poll. + * @retval NULL if no incoming message waiting. + * + * @sclass + */ +thread_t *chMsgPollS(void) { + thread_t *tp = NULL; + + if (chMsgIsPendingI(currp)) { + tp = queue_fifo_remove(&currp->msgqueue); + tp->state = CH_STATE_SNDMSG; + } + + 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 == CH_STATE_SNDMSG, "invalid state"); + chMsgReleaseS(tp, msg); + chSysUnlock(); +} + +#endif /* CH_CFG_USE_MESSAGES == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chmtx.c b/ChibiOS_20.3.2/os/rt/src/chmtx.c new file mode 100644 index 0000000..e7744f1 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chmtx.c @@ -0,0 +1,537 @@ +/* + 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 rt/src/chmtx.c + * @brief Mutexes code. + * + * @addtogroup mutexes + * @details Mutexes related APIs and services. + *

Operation mode

+ * A mutex is a threads synchronization object that can be in two + * distinct states: + * - Not owned (unlocked). + * - Owned by a thread (locked). + * . + * Operations defined for mutexes: + * - Lock: The mutex is checked, if the mutex is not owned by + * some other thread then it is associated to the locking thread + * else the thread is queued on the mutex in a list ordered by + * priority. + * - Unlock: The mutex is released by the owner and the highest + * priority thread waiting in the queue, if any, is resumed and made + * owner of the mutex. + * . + *

Constraints

+ * In ChibiOS/RT the Unlock operations must always be performed + * in lock-reverse order. This restriction both improves the + * performance and is required for an efficient implementation + * of the priority inheritance mechanism.
+ * Operating under this restriction also ensures that deadlocks + * are no possible. + * + *

Recursive mode

+ * By default mutexes are not recursive, this mean that it is not + * possible to take a mutex already owned by the same thread. + * It is possible to enable the recursive behavior by enabling the + * option @p CH_CFG_USE_MUTEXES_RECURSIVE. + * + *

The priority inversion problem

+ * The mutexes in ChibiOS/RT implements the full priority + * inheritance mechanism in order handle the priority inversion + * problem.
+ * When a thread is queued on a mutex, any thread, directly or + * indirectly, holding the mutex gains the same priority of the + * waiting thread (if their priority was not already equal or higher). + * The mechanism works with any number of nested mutexes and any + * number of involved threads. The algorithm complexity (worst case) + * is N with N equal to the number of nested mutexes. + * @pre In order to use the mutex APIs the @p CH_CFG_USE_MUTEXES option + * must be enabled in @p chconf.h. + * @post Enabling mutexes requires 5-12 (depending on the architecture) + * extra bytes in the @p thread_t structure. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes s @p mutex_t structure. + * + * @param[out] mp pointer to a @p mutex_t structure + * + * @init + */ +void chMtxObjectInit(mutex_t *mp) { + + chDbgCheck(mp != NULL); + + queue_init(&mp->queue); + mp->owner = NULL; +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + mp->cnt = (cnt_t)0; +#endif +} + +/** + * @brief Locks the specified mutex. + * @post The mutex is locked and inserted in the per-thread stack of owned + * mutexes. + * + * @param[in] mp pointer to the @p mutex_t structure + * + * @api + */ +void chMtxLock(mutex_t *mp) { + + chSysLock(); + chMtxLockS(mp); + chSysUnlock(); +} + +/** + * @brief Locks the specified mutex. + * @post The mutex is locked and inserted in the per-thread stack of owned + * mutexes. + * + * @param[in] mp pointer to the @p mutex_t structure + * + * @sclass + */ +void chMtxLockS(mutex_t *mp) { + thread_t *ctp = currp; + + chDbgCheckClassS(); + chDbgCheck(mp != NULL); + + /* Is the mutex already locked? */ + if (mp->owner != NULL) { +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + + chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive"); + + /* If the mutex is already owned by this thread, the counter is increased + and there is no need of more actions.*/ + if (mp->owner == ctp) { + mp->cnt++; + } + else { +#endif + /* Priority inheritance protocol; explores the thread-mutex dependencies + boosting the priority of all the affected threads to equal the + priority of the running thread requesting the mutex.*/ + thread_t *tp = mp->owner; + + /* Does the running thread have higher priority than the mutex + owning thread? */ + while (tp->prio < ctp->prio) { + /* Make priority of thread tp match the running thread's priority.*/ + tp->prio = ctp->prio; + + /* The following states need priority queues reordering.*/ + switch (tp->state) { + case CH_STATE_WTMTX: + /* Re-enqueues the mutex owner with its new priority.*/ + queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue); + tp = tp->u.wtmtxp->owner; + /*lint -e{9042} [16.1] Continues the while.*/ + continue; +#if (CH_CFG_USE_CONDVARS == TRUE) || \ + ((CH_CFG_USE_SEMAPHORES == TRUE) && \ + (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE)) || \ + ((CH_CFG_USE_MESSAGES == TRUE) && \ + (CH_CFG_USE_MESSAGES_PRIORITY == TRUE)) +#if CH_CFG_USE_CONDVARS == TRUE + case CH_STATE_WTCOND: +#endif +#if (CH_CFG_USE_SEMAPHORES == TRUE) && \ + (CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE) + case CH_STATE_WTSEM: +#endif +#if (CH_CFG_USE_MESSAGES == TRUE) && (CH_CFG_USE_MESSAGES_PRIORITY == TRUE) + case CH_STATE_SNDMSGQ: +#endif + /* Re-enqueues tp with its new priority on the queue.*/ + queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue); + break; +#endif + case CH_STATE_READY: +#if CH_DBG_ENABLE_ASSERTS == TRUE + /* Prevents an assertion in chSchReadyI().*/ + tp->state = CH_STATE_CURRENT; +#endif + /* Re-enqueues tp with its new priority on the ready list.*/ + (void) chSchReadyI(queue_dequeue(tp)); + break; + default: + /* Nothing to do for other states.*/ + break; + } + break; + } + + /* Sleep on the mutex.*/ + queue_prio_insert(ctp, &mp->queue); + ctp->u.wtmtxp = mp; + chSchGoSleepS(CH_STATE_WTMTX); + + /* It is assumed that the thread performing the unlock operation assigns + the mutex to this thread.*/ + chDbgAssert(mp->owner == ctp, "not owner"); + chDbgAssert(ctp->mtxlist == mp, "not owned"); +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + chDbgAssert(mp->cnt == (cnt_t)1, "counter is not one"); + } +#endif + } + else { +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero"); + + mp->cnt++; +#endif + /* It was not owned, inserted in the owned mutexes list.*/ + mp->owner = ctp; + mp->next = ctp->mtxlist; + ctp->mtxlist = mp; + } +} + +/** + * @brief Tries to lock a mutex. + * @details This function attempts to lock a mutex, if the mutex is already + * locked by another thread then the function exits without waiting. + * @post The mutex is locked and inserted in the per-thread stack of owned + * mutexes. + * @note This function does not have any overhead related to the + * priority inheritance mechanism because it does not try to + * enter a sleep state. + * + * @param[in] mp pointer to the @p mutex_t structure + * @return The operation status. + * @retval true if the mutex has been successfully acquired + * @retval false if the lock attempt failed. + * + * @api + */ +bool chMtxTryLock(mutex_t *mp) { + bool b; + + chSysLock(); + b = chMtxTryLockS(mp); + chSysUnlock(); + + return b; +} + +/** + * @brief Tries to lock a mutex. + * @details This function attempts to lock a mutex, if the mutex is already + * taken by another thread then the function exits without waiting. + * @post The mutex is locked and inserted in the per-thread stack of owned + * mutexes. + * @note This function does not have any overhead related to the + * priority inheritance mechanism because it does not try to + * enter a sleep state. + * + * @param[in] mp pointer to the @p mutex_t structure + * @return The operation status. + * @retval true if the mutex has been successfully acquired + * @retval false if the lock attempt failed. + * + * @sclass + */ +bool chMtxTryLockS(mutex_t *mp) { + + chDbgCheckClassS(); + chDbgCheck(mp != NULL); + + if (mp->owner != NULL) { +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + + chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive"); + + if (mp->owner == currp) { + mp->cnt++; + return true; + } +#endif + return false; + } +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + + chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero"); + + mp->cnt++; +#endif + mp->owner = currp; + mp->next = currp->mtxlist; + currp->mtxlist = mp; + return true; +} + +/** + * @brief Unlocks the specified mutex. + * @note Mutexes must be unlocked in reverse lock order. Violating this + * rules will result in a panic if assertions are enabled. + * @pre The invoking thread must have at least one owned mutex. + * @post The mutex is unlocked and removed from the per-thread stack of + * owned mutexes. + * + * @param[in] mp pointer to the @p mutex_t structure + * + * @api + */ +void chMtxUnlock(mutex_t *mp) { + thread_t *ctp = currp; + mutex_t *lmp; + + chDbgCheck(mp != NULL); + + chSysLock(); + + chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty"); + chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure"); +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive"); + + if (--mp->cnt == (cnt_t)0) { +#endif + + chDbgAssert(ctp->mtxlist == mp, "not next in list"); + + /* Removes the top mutex from the thread's owned mutexes list and marks + it as not owned. Note, it is assumed to be the same mutex passed as + parameter of this function.*/ + ctp->mtxlist = mp->next; + + /* If a thread is waiting on the mutex then the fun part begins.*/ + if (chMtxQueueNotEmptyS(mp)) { + thread_t *tp; + + /* Recalculates the optimal thread priority by scanning the owned + mutexes list.*/ + tprio_t newprio = ctp->realprio; + lmp = ctp->mtxlist; + while (lmp != NULL) { + /* If the highest priority thread waiting in the mutexes list has a + greater priority than the current thread base priority then the + final priority will have at least that priority.*/ + if (chMtxQueueNotEmptyS(lmp) && + (lmp->queue.next->prio > newprio)) { + newprio = lmp->queue.next->prio; + } + lmp = lmp->next; + } + + /* Assigns to the current thread the highest priority among all the + waiting threads.*/ + ctp->prio = newprio; + + /* Awakens the highest priority thread waiting for the unlocked mutex and + assigns the mutex to it.*/ +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + mp->cnt = (cnt_t)1; +#endif + tp = queue_fifo_remove(&mp->queue); + mp->owner = tp; + mp->next = tp->mtxlist; + tp->mtxlist = mp; + + /* Note, not using chSchWakeupS() because that function expects the + current thread to have the higher or equal priority than the ones + in the ready list. This is not necessarily true here because we + just changed priority.*/ + (void) chSchReadyI(tp); + chSchRescheduleS(); + } + else { + mp->owner = NULL; + } +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + } +#endif + + chSysUnlock(); +} + +/** + * @brief Unlocks the specified mutex. + * @note Mutexes must be unlocked in reverse lock order. Violating this + * rules will result in a panic if assertions are enabled. + * @pre The invoking thread must have at least one owned mutex. + * @post The mutex is unlocked and removed from the per-thread stack of + * owned mutexes. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. + * + * @param[in] mp pointer to the @p mutex_t structure + * + * @sclass + */ +void chMtxUnlockS(mutex_t *mp) { + thread_t *ctp = currp; + mutex_t *lmp; + + chDbgCheckClassS(); + chDbgCheck(mp != NULL); + + chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty"); + chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure"); +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive"); + + if (--mp->cnt == (cnt_t)0) { +#endif + + chDbgAssert(ctp->mtxlist == mp, "not next in list"); + + /* Removes the top mutex from the thread's owned mutexes list and marks + it as not owned. Note, it is assumed to be the same mutex passed as + parameter of this function.*/ + ctp->mtxlist = mp->next; + + /* If a thread is waiting on the mutex then the fun part begins.*/ + if (chMtxQueueNotEmptyS(mp)) { + thread_t *tp; + + /* Recalculates the optimal thread priority by scanning the owned + mutexes list.*/ + tprio_t newprio = ctp->realprio; + lmp = ctp->mtxlist; + while (lmp != NULL) { + /* If the highest priority thread waiting in the mutexes list has a + greater priority than the current thread base priority then the + final priority will have at least that priority.*/ + if (chMtxQueueNotEmptyS(lmp) && + (lmp->queue.next->prio > newprio)) { + newprio = lmp->queue.next->prio; + } + lmp = lmp->next; + } + + /* Assigns to the current thread the highest priority among all the + waiting threads.*/ + ctp->prio = newprio; + + /* Awakens the highest priority thread waiting for the unlocked mutex and + assigns the mutex to it.*/ +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + mp->cnt = (cnt_t)1; +#endif + tp = queue_fifo_remove(&mp->queue); + mp->owner = tp; + mp->next = tp->mtxlist; + tp->mtxlist = mp; + (void) chSchReadyI(tp); + } + else { + mp->owner = NULL; + } +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + } +#endif +} + +/** + * @brief Unlocks all mutexes owned by the invoking thread. + * @post The stack of owned mutexes is emptied and all the found + * mutexes are unlocked. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. + * @note This function is MUCH MORE efficient than releasing the + * mutexes one by one and not just because the call overhead, + * this function does not have any overhead related to the priority + * inheritance mechanism. + * + * @sclass + */ +void chMtxUnlockAllS(void) { + thread_t *ctp = currp; + + if (ctp->mtxlist != NULL) { + do { + mutex_t *mp = ctp->mtxlist; + ctp->mtxlist = mp->next; + if (chMtxQueueNotEmptyS(mp)) { + thread_t *tp; +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + mp->cnt = (cnt_t)1; +#endif + tp = queue_fifo_remove(&mp->queue); + mp->owner = tp; + mp->next = tp->mtxlist; + tp->mtxlist = mp; + (void) chSchReadyI(tp); + } + else { +#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE + mp->cnt = (cnt_t)0; +#endif + mp->owner = NULL; + } + } while (ctp->mtxlist != NULL); + ctp->prio = ctp->realprio; + chSchRescheduleS(); + } +} + +/** + * @brief Unlocks all mutexes owned by the invoking thread. + * @post The stack of owned mutexes is emptied and all the found + * mutexes are unlocked. + * @note This function is MUCH MORE efficient than releasing the + * mutexes one by one and not just because the call overhead, + * this function does not have any overhead related to the priority + * inheritance mechanism. + * + * @api + */ +void chMtxUnlockAll(void) { + + chSysLock(); + chMtxUnlockAllS(); + chSysUnlock(); +} + +#endif /* CH_CFG_USE_MUTEXES == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chregistry.c b/ChibiOS_20.3.2/os/rt/src/chregistry.c new file mode 100644 index 0000000..69be197 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chregistry.c @@ -0,0 +1,268 @@ +/* + 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 rt/src/chregistry.c + * @brief Threads registry code. + * + * @addtogroup registry + * @details Threads Registry related APIs and services. + *

Operation mode

+ * The Threads Registry is a double linked list that holds all the + * active threads in the system.
+ * Operations defined for the registry: + * - First, returns the first, in creation order, active thread + * in the system. + * - Next, returns the next, in creation order, active thread + * in the system. + * . + * The registry is meant to be mainly a debug feature, for example, + * using the registry a debugger can enumerate the active threads + * in any given moment or the shell can print the active threads + * and their state.
+ * Another possible use is for centralized threads memory management, + * terminating threads can pulse an event source and an event handler + * can perform a scansion of the registry in order to recover the + * memory. + * @pre In order to use the threads registry the @p CH_CFG_USE_REGISTRY + * option must be enabled in @p chconf.h. + * @{ + */ + +#include + +#include "ch.h" + +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#define _offsetof(st, m) \ + /*lint -save -e9005 -e9033 -e413 [11.8, 10.8 1.3] Normal pointers + arithmetic, it is safe.*/ \ + ((size_t)((char *)&((st *)0)->m - (char *)0)) \ + /*lint -restore*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/* + * OS signature in ROM plus debug-related information. + */ +ROMCONST chdebug_t ch_debug = { + {'m', 'a', 'i', 'n'}, + (uint8_t)0, + (uint8_t)sizeof (chdebug_t), + (uint16_t)(((unsigned)CH_KERNEL_MAJOR << 11U) | + ((unsigned)CH_KERNEL_MINOR << 6U) | + ((unsigned)CH_KERNEL_PATCH << 0U)), + (uint8_t)sizeof (void *), + (uint8_t)sizeof (systime_t), + (uint8_t)sizeof (thread_t), + (uint8_t)_offsetof(thread_t, prio), + (uint8_t)_offsetof(thread_t, ctx), + (uint8_t)_offsetof(thread_t, newer), + (uint8_t)_offsetof(thread_t, older), + (uint8_t)_offsetof(thread_t, name), +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) + (uint8_t)_offsetof(thread_t, wabase), +#else + (uint8_t)0, +#endif + (uint8_t)_offsetof(thread_t, state), + (uint8_t)_offsetof(thread_t, flags), +#if CH_CFG_USE_DYNAMIC == TRUE + (uint8_t)_offsetof(thread_t, refs), +#else + (uint8_t)0, +#endif +#if CH_CFG_TIME_QUANTUM > 0 + (uint8_t)_offsetof(thread_t, ticks), +#else + (uint8_t)0, +#endif +#if CH_DBG_THREADS_PROFILING == TRUE + (uint8_t)_offsetof(thread_t, time) +#else + (uint8_t)0 +#endif +}; + +/** + * @brief Returns the first thread in the system. + * @details Returns the most ancient thread in the system, usually this is + * the main thread unless it terminated. A reference is added to the + * returned thread in order to make sure its status is not lost. + * @note This function cannot return @p NULL because there is always at + * least one thread in the system. + * + * @return A reference to the most ancient thread. + * + * @api + */ +thread_t *chRegFirstThread(void) { + thread_t *tp; + + chSysLock(); + tp = ch.rlist.newer; +#if CH_CFG_USE_DYNAMIC == TRUE + tp->refs++; +#endif + chSysUnlock(); + + return tp; +} + +/** + * @brief Returns the thread next to the specified one. + * @details The reference counter of the specified thread is decremented and + * the reference counter of the returned thread is incremented. + * + * @param[in] tp pointer to the thread + * @return A reference to the next thread. + * @retval NULL if there is no next thread. + * + * @api + */ +thread_t *chRegNextThread(thread_t *tp) { + thread_t *ntp; + + chSysLock(); + ntp = tp->newer; + /*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/ + if (ntp == (thread_t *)&ch.rlist) { + /*lint -restore*/ + ntp = NULL; + } +#if CH_CFG_USE_DYNAMIC == TRUE + else { + chDbgAssert(ntp->refs < (trefs_t)255, "too many references"); + ntp->refs++; + } +#endif + chSysUnlock(); +#if CH_CFG_USE_DYNAMIC == TRUE + chThdRelease(tp); +#endif + + return ntp; +} + +/** + * @brief Retrieves a thread pointer by name. + * @note The reference counter of the found thread is increased by one so + * it cannot be disposed incidentally after the pointer has been + * returned. + * + * @param[in] name the thread name + * @return A pointer to the found thread. + * @retval NULL if a matching thread has not been found. + * + * @api + */ +thread_t *chRegFindThreadByName(const char *name) { + thread_t *ctp; + + /* Scanning registry.*/ + ctp = chRegFirstThread(); + do { + if (strcmp(chRegGetThreadNameX(ctp), name) == 0) { + return ctp; + } + ctp = chRegNextThread(ctp); + } while (ctp != NULL); + + return NULL; +} + +/** + * @brief Confirms that a pointer is a valid thread pointer. + * @note The reference counter of the found thread is increased by one so + * it cannot be disposed incidentally after the pointer has been + * returned. + * + * @param[in] tp pointer to the thread + * @return A pointer to the found thread. + * @retval NULL if a matching thread has not been found. + * + * @api + */ +thread_t *chRegFindThreadByPointer(thread_t *tp) { + thread_t *ctp; + + /* Scanning registry.*/ + ctp = chRegFirstThread(); + do { + if (ctp == tp) { + return ctp; + } + ctp = chRegNextThread(ctp); + } while (ctp != NULL); + + return NULL; +} + +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \ + defined(__DOXYGEN__) +/** + * @brief Confirms that a working area is being used by some active thread. + * @note The reference counter of the found thread is increased by one so + * it cannot be disposed incidentally after the pointer has been + * returned. + * + * @param[in] wa pointer to a static working area + * @return A pointer to the found thread. + * @retval NULL if a matching thread has not been found. + * + * @api + */ +thread_t *chRegFindThreadByWorkingArea(stkalign_t *wa) { + thread_t *ctp; + + /* Scanning registry.*/ + ctp = chRegFirstThread(); + do { + if (chThdGetWorkingAreaX(ctp) == wa) { + return ctp; + } + ctp = chRegNextThread(ctp); + } while (ctp != NULL); + + return NULL; +} +#endif + +#endif /* CH_CFG_USE_REGISTRY == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chschd.c b/ChibiOS_20.3.2/os/rt/src/chschd.c new file mode 100644 index 0000000..540b1c2 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chschd.c @@ -0,0 +1,610 @@ +/* + 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 rt/src/chschd.c + * @brief Scheduler code. + * + * @addtogroup scheduler + * @details This module provides the default portable scheduler code. + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief System data structures. + */ +ch_system_t ch; + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Scheduler initialization. + * + * @notapi + */ +void _scheduler_init(void) { + + queue_init(&ch.rlist.queue); + ch.rlist.prio = NOPRIO; +#if CH_CFG_USE_REGISTRY == TRUE + ch.rlist.newer = (thread_t *)&ch.rlist; + ch.rlist.older = (thread_t *)&ch.rlist; +#endif +} + +#if (CH_CFG_OPTIMIZE_SPEED == FALSE) || defined(__DOXYGEN__) +/** + * @brief Inserts a thread into a priority ordered queue. + * @note The insertion is done by scanning the list from the highest + * priority toward the lowest. + * + * @param[in] tp the pointer to the thread to be inserted in the list + * @param[in] tqp the pointer to the threads list header + * + * @notapi + */ +void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) { + + thread_t *cp = (thread_t *)tqp; + do { + cp = cp->queue.next; + } while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio)); + tp->queue.next = cp; + tp->queue.prev = cp->queue.prev; + tp->queue.prev->queue.next = tp; + cp->queue.prev = tp; +} + +/** + * @brief Inserts a thread into a queue. + * + * @param[in] tp the pointer to the thread to be inserted in the list + * @param[in] tqp the pointer to the threads list header + * + * @notapi + */ +void queue_insert(thread_t *tp, threads_queue_t *tqp) { + + tp->queue.next = (thread_t *)tqp; + tp->queue.prev = tqp->prev; + tp->queue.prev->queue.next = tp; + tqp->prev = tp; +} + +/** + * @brief Removes the first-out thread from a queue and returns it. + * @note If the queue is priority ordered then this function returns the + * thread with the highest priority. + * + * @param[in] tqp the pointer to the threads list header + * @return The removed thread pointer. + * + * @notapi + */ +thread_t *queue_fifo_remove(threads_queue_t *tqp) { + thread_t *tp = tqp->next; + + tqp->next = tp->queue.next; + tqp->next->queue.prev = (thread_t *)tqp; + + return tp; +} + +/** + * @brief Removes the last-out thread from a queue and returns it. + * @note If the queue is priority ordered then this function returns the + * thread with the lowest priority. + * + * @param[in] tqp the pointer to the threads list header + * @return The removed thread pointer. + * + * @notapi + */ +thread_t *queue_lifo_remove(threads_queue_t *tqp) { + thread_t *tp = tqp->prev; + + tqp->prev = tp->queue.prev; + tqp->prev->queue.next = (thread_t *)tqp; + + return tp; +} + +/** + * @brief Removes a thread from a queue and returns it. + * @details The thread is removed from the queue regardless of its relative + * position and regardless the used insertion method. + * + * @param[in] tp the pointer to the thread to be removed from the queue + * @return The removed thread pointer. + * + * @notapi + */ +thread_t *queue_dequeue(thread_t *tp) { + + tp->queue.prev->queue.next = tp->queue.next; + tp->queue.next->queue.prev = tp->queue.prev; + + return tp; +} + +/** + * @brief Pushes a thread_t on top of a stack list. + * + * @param[in] tp the pointer to the thread to be inserted in the list + * @param[in] tlp the pointer to the threads list header + * + * @notapi + */ +void list_insert(thread_t *tp, threads_list_t *tlp) { + + tp->queue.next = tlp->next; + tlp->next = tp; +} + +/** + * @brief Pops a thread from the top of a stack list and returns it. + * @pre The list must be non-empty before calling this function. + * + * @param[in] tlp the pointer to the threads list header + * @return The removed thread pointer. + * + * @notapi + */ +thread_t *list_remove(threads_list_t *tlp) { + + thread_t *tp = tlp->next; + tlp->next = tp->queue.next; + + return tp; +} +#endif /* CH_CFG_OPTIMIZE_SPEED */ + +/** + * @brief Inserts a thread in the Ready List placing it behind its peers. + * @details The thread is positioned behind all threads with higher or equal + * priority. + * @pre The thread must not be already inserted in any list through its + * @p next and @p prev or list corruption would occur. + * @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 made ready + * @return The thread pointer. + * + * @iclass + */ +thread_t *chSchReadyI(thread_t *tp) { + thread_t *cp; + + chDbgCheckClassI(); + chDbgCheck(tp != NULL); + chDbgAssert((tp->state != CH_STATE_READY) && + (tp->state != CH_STATE_FINAL), + "invalid state"); + + tp->state = CH_STATE_READY; + cp = (thread_t *)&ch.rlist.queue; + do { + cp = cp->queue.next; + } while (cp->prio >= tp->prio); + /* Insertion on prev.*/ + tp->queue.next = cp; + tp->queue.prev = cp->queue.prev; + tp->queue.prev->queue.next = tp; + cp->queue.prev = tp; + + return tp; +} + +/** + * @brief Inserts a thread in the Ready List placing it ahead its peers. + * @details The thread is positioned ahead all threads with higher or equal + * priority. + * @pre The thread must not be already inserted in any list through its + * @p next and @p prev or list corruption would occur. + * @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 made ready + * @return The thread pointer. + * + * @iclass + */ +thread_t *chSchReadyAheadI(thread_t *tp) { + thread_t *cp; + + chDbgCheckClassI(); + chDbgCheck(tp != NULL); + chDbgAssert((tp->state != CH_STATE_READY) && + (tp->state != CH_STATE_FINAL), + "invalid state"); + + tp->state = CH_STATE_READY; + cp = (thread_t *)&ch.rlist.queue; + do { + cp = cp->queue.next; + } while (cp->prio > tp->prio); + /* Insertion on prev.*/ + tp->queue.next = cp; + tp->queue.prev = cp->queue.prev; + tp->queue.prev->queue.next = tp; + cp->queue.prev = tp; + + return tp; +} + +/** + * @brief Puts the current thread to sleep into the specified state. + * @details The thread goes into a sleeping state. The possible + * @ref thread_states are defined into @p threads.h. + * + * @param[in] newstate the new thread state + * + * @sclass + */ +void chSchGoSleepS(tstate_t newstate) { + thread_t *otp = currp; + + chDbgCheckClassS(); + + /* New state.*/ + otp->state = newstate; + +#if CH_CFG_TIME_QUANTUM > 0 + /* The thread is renouncing its remaining time slices so it will have a new + time quantum when it will wakeup.*/ + otp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM; +#endif + + /* Next thread in ready list becomes current.*/ + currp = queue_fifo_remove(&ch.rlist.queue); + currp->state = CH_STATE_CURRENT; + + /* Handling idle-enter hook.*/ + if (currp->prio == IDLEPRIO) { + CH_CFG_IDLE_ENTER_HOOK(); + } + + /* Swap operation as tail call.*/ + chSysSwitch(currp, otp); +} + +/* + * Timeout wakeup callback. + */ +static void wakeup(void *p) { + thread_t *tp = (thread_t *)p; + + chSysLockFromISR(); + switch (tp->state) { + case CH_STATE_READY: + /* Handling the special case where the thread has been made ready by + another thread with higher priority.*/ + chSysUnlockFromISR(); + return; + case CH_STATE_SUSPENDED: + *tp->u.wttrp = NULL; + break; +#if CH_CFG_USE_SEMAPHORES == TRUE + case CH_STATE_WTSEM: + chSemFastSignalI(tp->u.wtsemp); +#endif + /* Falls through.*/ + case CH_STATE_QUEUED: + /* Falls through.*/ +#if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE) + case CH_STATE_WTCOND: +#endif + /* States requiring dequeuing.*/ + (void) queue_dequeue(tp); + break; + default: + /* Any other state, nothing to do.*/ + break; + } + tp->u.rdymsg = MSG_TIMEOUT; + (void) chSchReadyI(tp); + chSysUnlockFromISR(); +} + +/** + * @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 timeout then it is forcibly + * awakened with a @p MSG_TIMEOUT low level message. The possible + * @ref thread_states are defined into @p threads.h. + * + * @param[in] newstate the new thread state + * @param[in] timeout the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state, this is equivalent to invoking + * @p chSchGoSleepS() but, of course, less efficient. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @return The wakeup message. + * @retval MSG_TIMEOUT if a timeout occurs. + * + * @sclass + */ +msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout) { + + chDbgCheckClassS(); + + if (TIME_INFINITE != timeout) { + virtual_timer_t vt; + + chVTDoSetI(&vt, timeout, wakeup, currp); + chSchGoSleepS(newstate); + if (chVTIsArmedI(&vt)) { + chVTDoResetI(&vt); + } + } + else { + chSchGoSleepS(newstate); + } + + return currp->u.rdymsg; +} + +/** + * @brief Wakes up a thread. + * @details The thread is inserted into the ready list or immediately made + * running depending on its relative priority compared to the current + * thread. + * @pre The thread must not be already inserted in any list through its + * @p next and @p prev or list corruption would occur. + * @note It is equivalent to a @p chSchReadyI() followed by a + * @p chSchRescheduleS() but much more efficient. + * @note The function assumes that the current thread has the highest + * priority. + * + * @param[in] ntp the thread to be made ready + * @param[in] msg the wakeup message + * + * @sclass + */ +void chSchWakeupS(thread_t *ntp, msg_t msg) { + thread_t *otp = currp; + + chDbgCheckClassS(); + + chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) || + (ch.rlist.current->prio >= ch.rlist.queue.next->prio), + "priority order violation"); + + /* Storing the message to be retrieved by the target thread when it will + restart execution.*/ + ntp->u.rdymsg = msg; + + /* If the waken thread has a not-greater priority than the current + one then it is just inserted in the ready list else it made + running immediately and the invoking thread goes in the ready + list instead.*/ + if (ntp->prio <= otp->prio) { + (void) chSchReadyI(ntp); + } + else { + otp = chSchReadyAheadI(otp); + + /* Handling idle-leave hook.*/ + if (otp->prio == IDLEPRIO) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + + /* The extracted thread is marked as current.*/ + currp = ntp; + ntp->state = CH_STATE_CURRENT; + + /* Swap operation as tail call.*/ + chSysSwitch(ntp, otp); + } +} + +/** + * @brief Performs a reschedule if a higher priority thread is runnable. + * @details If a thread with a higher priority than the current thread is in + * the ready list then make the higher priority thread running. + * + * @sclass + */ +void chSchRescheduleS(void) { + + chDbgCheckClassS(); + + if (chSchIsRescRequiredI()) { + chSchDoRescheduleAhead(); + } +} + +#if !defined(CH_SCH_IS_PREEMPTION_REQUIRED_HOOKED) +/** + * @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) { + tprio_t p1 = firstprio(&ch.rlist.queue); + tprio_t p2 = currp->prio; + +#if CH_CFG_TIME_QUANTUM > 0 + /* If the running thread has not reached its time quantum, reschedule only + if the first thread on the ready queue has a higher priority. + Otherwise, if the running thread has used up its time quantum, reschedule + if the first thread on the ready queue has equal or higher priority.*/ + return (currp->ticks > (tslices_t)0) ? (p1 > p2) : (p1 >= p2); +#else + /* If the round robin preemption feature is not enabled then performs a + simpler comparison.*/ + return p1 > p2; +#endif +} +#endif /* !defined(CH_SCH_IS_PREEMPTION_REQUIRED_HOOKED) */ + +/** + * @brief Switches to the first thread on the runnable queue. + * @details The current thread is positioned in the ready list behind all + * threads having the same priority. The thread regains its time + * quantum. + * @note Not a user function, it is meant to be invoked by the scheduler + * itself. + * + * @special + */ +void chSchDoRescheduleBehind(void) { + thread_t *otp = currp; + + /* Picks the first thread from the ready queue and makes it current.*/ + currp = queue_fifo_remove(&ch.rlist.queue); + currp->state = CH_STATE_CURRENT; + + /* Handling idle-leave hook.*/ + if (otp->prio == IDLEPRIO) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + +#if CH_CFG_TIME_QUANTUM > 0 + /* It went behind peers so it gets a new time quantum.*/ + otp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM; +#endif + + /* Placing in ready list behind peers.*/ + otp = chSchReadyI(otp); + + /* Swap operation as tail call.*/ + chSysSwitch(currp, otp); +} + +/** + * @brief Switches to the first thread on the runnable queue. + * @details The current thread is positioned in the ready list ahead of all + * threads having the same priority. + * @note Not a user function, it is meant to be invoked by the scheduler + * itself. + * + * @special + */ +void chSchDoRescheduleAhead(void) { + thread_t *otp = currp; + + /* Picks the first thread from the ready queue and makes it current.*/ + currp = queue_fifo_remove(&ch.rlist.queue); + currp->state = CH_STATE_CURRENT; + + /* Handling idle-leave hook.*/ + if (otp->prio == IDLEPRIO) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + + /* Placing in ready list ahead of peers.*/ + otp = chSchReadyAheadI(otp); + + /* Swap operation as tail call.*/ + chSysSwitch(currp, otp); +} + +#if !defined(CH_SCH_DO_RESCHEDULE_HOOKED) +/** + * @brief Switches to the first thread on the runnable queue. + * @details The current thread is positioned in the ready list behind or + * ahead of all threads having the same priority depending on + * if it used its whole time slice. + * @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 = currp; + + /* Picks the first thread from the ready queue and makes it current.*/ + currp = queue_fifo_remove(&ch.rlist.queue); + currp->state = CH_STATE_CURRENT; + + /* Handling idle-leave hook.*/ + if (otp->prio == IDLEPRIO) { + CH_CFG_IDLE_LEAVE_HOOK(); + } + +#if CH_CFG_TIME_QUANTUM > 0 + /* If CH_CFG_TIME_QUANTUM is enabled then there are two different scenarios + to handle on preemption: time quantum elapsed or not.*/ + if (otp->ticks == (tslices_t)0) { + + /* The thread consumed its time quantum so it is enqueued behind threads + with same priority level, however, it acquires a new time quantum.*/ + otp = chSchReadyI(otp); + + /* The thread being swapped out receives a new time quantum.*/ + otp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM; + } + else { + /* The thread didn't consume all its time quantum so it is put ahead of + threads with equal priority and does not acquire a new time quantum.*/ + otp = chSchReadyAheadI(otp); + } +#else /* !(CH_CFG_TIME_QUANTUM > 0) */ + /* If the round-robin mechanism is disabled then the thread goes always + ahead of its peers.*/ + otp = chSchReadyAheadI(otp); +#endif /* !(CH_CFG_TIME_QUANTUM > 0) */ + + /* Swap operation as tail call.*/ + chSysSwitch(currp, otp); +} +#endif /* !defined(CH_SCH_DO_RESCHEDULE_HOOKED) */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chsem.c b/ChibiOS_20.3.2/os/rt/src/chsem.c new file mode 100644 index 0000000..7671aec --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chsem.c @@ -0,0 +1,405 @@ +/* + 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 rt/src/chsem.c + * @brief Semaphores code. + * + * @addtogroup semaphores + * @details Semaphores related APIs and services. + *

Operation mode

+ * Semaphores are a flexible synchronization primitive, ChibiOS/RT + * implements semaphores in their "counting semaphores" variant as + * defined by Edsger Dijkstra plus several enhancements like: + * - Wait operation with timeout. + * - Reset operation. + * - Atomic wait+signal operation. + * - Return message from the wait operation (OK, RESET, TIMEOUT). + * . + * The binary semaphores variant can be easily implemented using + * counting semaphores.
+ * Operations defined for semaphores: + * - Signal: The semaphore counter is increased and if the + * result is non-positive then a waiting thread is removed from + * the semaphore queue and made ready for execution. + * - Wait: The semaphore counter is decreased and if the result + * becomes negative the thread is queued in the semaphore and + * suspended. + * - Reset: The semaphore counter is reset to a non-negative + * value and all the threads in the queue are released. + * . + * Semaphores can be used as guards for mutual exclusion zones + * (note that mutexes are recommended for this kind of use) but + * also have other uses, queues guards and counters for example.
+ * Semaphores usually use a FIFO queuing strategy but it is possible + * to make them order threads by priority by enabling + * @p CH_CFG_USE_SEMAPHORES_PRIORITY in @p chconf.h. + * @pre In order to use the semaphore APIs the @p CH_CFG_USE_SEMAPHORES + * option must be enabled in @p chconf.h. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE +#define sem_insert(tp, qp) queue_prio_insert(tp, qp) +#else +#define sem_insert(tp, qp) queue_insert(tp, qp) +#endif + +/*===========================================================================*/ +/* Module exported 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 + */ +void chSemObjectInit(semaphore_t *sp, cnt_t n) { + + chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); + + queue_init(&sp->queue); + 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. + * + * @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) { + + chDbgCheckClassI(); + chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + + sp->cnt = n; + while (queue_notempty(&sp->queue)) { + chSchReadyI(queue_lifo_remove(&sp->queue))->u.rdymsg = msg; + } +} + +/** + * @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 MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval MSG_RESET if the semaphore has been reset using @p chSemReset(). + * + * @api + */ +msg_t chSemWait(semaphore_t *sp) { + msg_t msg; + + chSysLock(); + msg = chSemWaitS(sp); + chSysUnlock(); + + return msg; +} + +/** + * @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 MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval MSG_RESET if the semaphore has been reset using @p chSemReset(). + * + * @sclass + */ +msg_t chSemWaitS(semaphore_t *sp) { + + chDbgCheckClassS(); + chDbgCheck(sp != NULL); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + + if (--sp->cnt < (cnt_t)0) { + currp->u.wtsemp = sp; + sem_insert(currp, &sp->queue); + chSchGoSleepS(CH_STATE_WTSEM); + + return currp->u.rdymsg; + } + + return MSG_OK; +} + +/** + * @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 MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval MSG_RESET if the semaphore has been reset using @p chSemReset(). + * @retval MSG_TIMEOUT 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 MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval MSG_RESET if the semaphore has been reset using @p chSemReset(). + * @retval MSG_TIMEOUT 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); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + + if (--sp->cnt < (cnt_t)0) { + if (TIME_IMMEDIATE == timeout) { + sp->cnt++; + + return MSG_TIMEOUT; + } + currp->u.wtsemp = sp; + sem_insert(currp, &sp->queue); + + return chSchGoSleepTimeoutS(CH_STATE_WTSEM, timeout); + } + + 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) { + + chDbgCheck(sp != NULL); + + chSysLock(); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + if (++sp->cnt <= (cnt_t)0) { + chSchWakeupS(queue_fifo_remove(&sp->queue), MSG_OK); + } + 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); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + + if (++sp->cnt <= (cnt_t)0) { + /* Note, it is done this way in order to allow a tail call on + chSchReadyI().*/ + thread_t *tp = queue_fifo_remove(&sp->queue); + tp->u.rdymsg = MSG_OK; + (void) chSchReadyI(tp); + } +} + +/** + * @brief Adds the specified value to the semaphore counter. + * @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 value to be added to the semaphore counter. The value + * must be positive. + * + * @iclass + */ +void chSemAddCounterI(semaphore_t *sp, cnt_t n) { + + chDbgCheckClassI(); + chDbgCheck((sp != NULL) && (n > (cnt_t)0)); + chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) || + ((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)), + "inconsistent semaphore"); + + while (n > (cnt_t)0) { + if (++sp->cnt <= (cnt_t)0) { + chSchReadyI(queue_fifo_remove(&sp->queue))->u.rdymsg = MSG_OK; + } + n--; + } +} + +/** + * @brief Performs atomic signal and wait operations on two semaphores. + * + * @param[in] sps pointer to a @p semaphore_t structure to be signaled + * @param[in] spw pointer to a @p semaphore_t structure to wait on + * @return A message specifying how the invoking thread has been + * released from the semaphore. + * @retval MSG_OK if the thread has not stopped on the semaphore or the + * semaphore has been signaled. + * @retval MSG_RESET if the semaphore has been reset using @p chSemReset(). + * + * @api + */ +msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw) { + msg_t msg; + + chDbgCheck((sps != NULL) && (spw != NULL)); + + chSysLock(); + chDbgAssert(((sps->cnt >= (cnt_t)0) && queue_isempty(&sps->queue)) || + ((sps->cnt < (cnt_t)0) && queue_notempty(&sps->queue)), + "inconsistent semaphore"); + chDbgAssert(((spw->cnt >= (cnt_t)0) && queue_isempty(&spw->queue)) || + ((spw->cnt < (cnt_t)0) && queue_notempty(&spw->queue)), + "inconsistent semaphore"); + if (++sps->cnt <= (cnt_t)0) { + chSchReadyI(queue_fifo_remove(&sps->queue))->u.rdymsg = MSG_OK; + } + if (--spw->cnt < (cnt_t)0) { + thread_t *ctp = currp; + sem_insert(ctp, &spw->queue); + ctp->u.wtsemp = spw; + chSchGoSleepS(CH_STATE_WTSEM); + msg = ctp->u.rdymsg; + } + else { + chSchRescheduleS(); + msg = MSG_OK; + } + chSysUnlock(); + + return msg; +} + +#endif /* CH_CFG_USE_SEMAPHORES == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chstats.c b/ChibiOS_20.3.2/os/rt/src/chstats.c new file mode 100644 index 0000000..5d3c0fc --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chstats.c @@ -0,0 +1,126 @@ +/* + 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 rt/src/chstats.c + * @brief Statistics module code. + * + * @addtogroup statistics + * @details Statistics services. + * @{ + */ + +#include "ch.h" + +#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes the statistics module. + * + * @init + */ +void _stats_init(void) { + + ch.kernel_stats.n_irq = (ucnt_t)0; + ch.kernel_stats.n_ctxswc = (ucnt_t)0; + chTMObjectInit(&ch.kernel_stats.m_crit_thd); + chTMObjectInit(&ch.kernel_stats.m_crit_isr); +} + +/** + * @brief Increases the IRQ counter. + */ +void _stats_increase_irq(void) { + + port_lock_from_isr(); + ch.kernel_stats.n_irq++; + port_unlock_from_isr(); +} + +/** + * @brief Updates context switch related statistics. + * + * @param[in] ntp the thread to be switched in + * @param[in] otp the thread to be switched out + */ +void _stats_ctxswc(thread_t *ntp, thread_t *otp) { + + ch.kernel_stats.n_ctxswc++; + chTMChainMeasurementToX(&otp->stats, &ntp->stats); +} + +/** + * @brief Starts the measurement of a thread critical zone. + */ +void _stats_start_measure_crit_thd(void) { + + chTMStartMeasurementX(&ch.kernel_stats.m_crit_thd); +} + +/** + * @brief Stops the measurement of a thread critical zone. + */ +void _stats_stop_measure_crit_thd(void) { + + chTMStopMeasurementX(&ch.kernel_stats.m_crit_thd); +} + +/** + * @brief Starts the measurement of an ISR critical zone. + */ +void _stats_start_measure_crit_isr(void) { + + chTMStartMeasurementX(&ch.kernel_stats.m_crit_isr); +} + +/** + * @brief Stops the measurement of an ISR critical zone. + */ +void _stats_stop_measure_crit_isr(void) { + + chTMStopMeasurementX(&ch.kernel_stats.m_crit_isr); +} + +#endif /* CH_DBG_STATISTICS == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chsys.c b/ChibiOS_20.3.2/os/rt/src/chsys.c new file mode 100644 index 0000000..cfe9321 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chsys.c @@ -0,0 +1,445 @@ +/* + 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 rt/src/chsys.c + * @brief System related code. + * + * @addtogroup system + * @details System related APIs and services: + * - Initialization. + * - Locks. + * - Interrupt Handling. + * - Power Management. + * - Abnormal Termination. + * - Realtime counter. + * . + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__) +/** + * @brief Idle thread working area. + */ +THD_WORKING_AREA(ch_idle_thread_wa, PORT_IDLE_THREAD_STACK_SIZE); +#endif + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__) +/** + * @brief This function implements the idle thread infinite loop. + * @details The function puts the processor in the lowest power mode capable + * to serve interrupts.
+ * The priority is internally set to the minimum system value so + * that this thread is executed only if there are no other ready + * threads in the system. + * + * @param[in] p the thread parameter, unused in this scenario + */ +static void _idle_thread(void *p) { + + (void)p; + + while (true) { + /*lint -save -e522 [2.2] Apparently no side effects because it contains + an asm instruction.*/ + port_wait_for_interrupt(); + /*lint -restore*/ + CH_CFG_IDLE_LOOP_HOOK(); + } +} +#endif /* CH_CFG_NO_IDLE_THREAD == FALSE */ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief ChibiOS/RT initialization. + * @details After executing this function the current instructions stream + * becomes the main thread. + * @pre Interrupts must disabled before invoking this function. + * @post The main thread is created with priority @p NORMALPRIO and + * interrupts are enabled. + * + * @special + */ +void chSysInit(void) { + + _scheduler_init(); + _vt_init(); + _trace_init(); + _oslib_init(); + +#if CH_DBG_SYSTEM_STATE_CHECK == TRUE + ch.dbg.isr_cnt = (cnt_t)0; + ch.dbg.lock_cnt = (cnt_t)0; +#endif +#if CH_CFG_USE_TM == TRUE + _tm_init(); +#endif +#if CH_DBG_STATISTICS == TRUE + _stats_init(); +#endif + +#if CH_CFG_NO_IDLE_THREAD == FALSE + /* Now this instructions flow becomes the main thread.*/ +#if CH_CFG_USE_REGISTRY == TRUE + currp = _thread_init(&ch.mainthread, (const char *)&ch_debug, NORMALPRIO); +#else + currp = _thread_init(&ch.mainthread, "main", NORMALPRIO); +#endif +#else + /* Now this instructions flow becomes the idle thread.*/ + currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO); +#endif + +#if CH_DBG_ENABLE_STACK_CHECK == TRUE + { + /* Setting up the base address of the static main thread stack, the + symbol must be provided externally.*/ + extern stkalign_t __main_thread_stack_base__; + currp->wabase = &__main_thread_stack_base__; + } +#elif CH_CFG_USE_DYNAMIC == TRUE + currp->wabase = NULL; +#endif + + /* Setting up the caller as current thread.*/ + currp->state = CH_STATE_CURRENT; + + /* Port layer initialization last because it depend on some of the + initializations performed before.*/ + port_init(); + +#if CH_DBG_STATISTICS == TRUE + /* Starting measurement for this thread.*/ + chTMStartMeasurementX(&currp->stats); +#endif + + /* Initialization hook.*/ + CH_CFG_SYSTEM_INIT_HOOK(); + + /* It is alive now.*/ + chSysEnable(); + +#if CH_CFG_NO_IDLE_THREAD == FALSE + { + static const thread_descriptor_t idle_descriptor = { + "idle", + THD_WORKING_AREA_BASE(ch_idle_thread_wa), + THD_WORKING_AREA_END(ch_idle_thread_wa), + IDLEPRIO, + _idle_thread, + NULL + }; + + /* This thread has the lowest priority in the system, its role is just to + serve interrupts in its context while keeping the lowest energy saving + mode compatible with the system status.*/ + (void) chThdCreate(&idle_descriptor); + } +#endif +} + +/** + * @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(); + + /* Logging the event.*/ + _trace_halt(reason); + + /* Pointing to the passed message.*/ + ch.dbg.panic_msg = reason; + + /* Halt hook code, usually empty.*/ + CH_CFG_SYSTEM_HALT_HOOK(reason); + + /* Harmless infinite loop.*/ + while (true) { + } +} + +/** + * @brief System integrity check. + * @details Performs an integrity check of the important ChibiOS/RT data + * structures. + * @note The appropriate action in case of failure is to halt the system + * before releasing the critical zone. + * @note If the system is corrupted then one possible outcome of this + * function is an exception caused by @p NULL or corrupted pointers + * in list elements. Exception vectors must be monitored as well. + * @note This function is not used internally, it is up to the + * application to define if and where to perform system + * checking. + * @note Performing all tests at once can be a slow operation and can + * degrade the system response time. It is suggested to execute + * one test at time and release the critical zone in between tests. + * + * @param[in] testmask Each bit in this mask is associated to a test to be + * performed. + * @return The test result. + * @retval false The test succeeded. + * @retval true Test failed. + * + * @iclass + */ +bool chSysIntegrityCheckI(unsigned testmask) { + cnt_t n; + + chDbgCheckClassI(); + + /* Ready List integrity check.*/ + if ((testmask & CH_INTEGRITY_RLIST) != 0U) { + thread_t *tp; + + /* Scanning the ready list forward.*/ + n = (cnt_t)0; + tp = ch.rlist.queue.next; + while (tp != (thread_t *)&ch.rlist.queue) { + n++; + tp = tp->queue.next; + } + + /* Scanning the ready list backward.*/ + tp = ch.rlist.queue.prev; + while (tp != (thread_t *)&ch.rlist.queue) { + n--; + tp = tp->queue.prev; + } + + /* The number of elements must match.*/ + if (n != (cnt_t)0) { + return true; + } + } + + /* Timers list integrity check.*/ + if ((testmask & CH_INTEGRITY_VTLIST) != 0U) { + virtual_timer_t * vtp; + + /* Scanning the timers list forward.*/ + n = (cnt_t)0; + vtp = ch.vtlist.next; + while (vtp != (virtual_timer_t *)&ch.vtlist) { + n++; + vtp = vtp->next; + } + + /* Scanning the timers list backward.*/ + vtp = ch.vtlist.prev; + while (vtp != (virtual_timer_t *)&ch.vtlist) { + n--; + vtp = vtp->prev; + } + + /* The number of elements must match.*/ + if (n != (cnt_t)0) { + return true; + } + } + +#if CH_CFG_USE_REGISTRY == TRUE + if ((testmask & CH_INTEGRITY_REGISTRY) != 0U) { + thread_t *tp; + + /* Scanning the ready list forward.*/ + n = (cnt_t)0; + tp = ch.rlist.newer; + while (tp != (thread_t *)&ch.rlist) { + n++; + tp = tp->newer; + } + + /* Scanning the ready list backward.*/ + tp = ch.rlist.older; + while (tp != (thread_t *)&ch.rlist) { + n--; + tp = tp->older; + } + + /* The number of elements must match.*/ + if (n != (cnt_t)0) { + return true; + } + } +#endif /* CH_CFG_USE_REGISTRY == TRUE */ + +#if defined(PORT_INTEGRITY_CHECK) + if ((testmask & CH_INTEGRITY_PORT) != 0U) { + PORT_INTEGRITY_CHECK(); + } +#endif + + return false; +} + +/** + * @brief Handles time ticks for round robin preemption and timer increments. + * @details Decrements the remaining time quantum of the running thread + * and preempts it when the quantum is used up. Increments system + * time and manages the timers. + * @note The frequency of the timer determines the system tick granularity + * and, together with the @p CH_CFG_TIME_QUANTUM macro, the round robin + * interval. + * + * @iclass + */ +void chSysTimerHandlerI(void) { + + chDbgCheckClassI(); + +#if CH_CFG_TIME_QUANTUM > 0 + /* Running thread has not used up quantum yet? */ + if (currp->ticks > (tslices_t)0) { + /* Decrement remaining quantum.*/ + currp->ticks--; + } +#endif +#if CH_DBG_THREADS_PROFILING == TRUE + currp->time++; +#endif + chVTDoTickI(); + CH_CFG_SYSTEM_TICK_HOOK(); +} + +/** + * @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 */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chthreads.c b/ChibiOS_20.3.2/os/rt/src/chthreads.c new file mode 100644 index 0000000..caa846b --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chthreads.c @@ -0,0 +1,906 @@ +/* + 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 rt/src/chthreads.c + * @brief Threads code. + * + * @addtogroup threads + * @details Threads related APIs and services. + *

Operation mode

+ * A thread is an abstraction of an independent instructions flow. + * In ChibiOS/RT a thread is represented by a "C" function owning + * a processor context, state informations and a dedicated stack + * area. In this scenario static variables are shared among all + * threads while automatic variables are local to the thread.
+ * Operations defined for threads: + * - Create, a thread is started on the specified thread + * function. This operation is available in multiple variants, + * both static and dynamic. + * - Exit, a thread terminates by returning from its top + * level function or invoking a specific API, the thread can + * return a value that can be retrieved by other threads. + * - Wait, a thread waits for the termination of another + * thread and retrieves its return value. + * - Resume, a thread created in suspended state is started. + * - Sleep, the execution of a thread is suspended for the + * specified amount of time or the specified future absolute time + * is reached. + * - SetPriority, a thread changes its own priority level. + * - Yield, a thread voluntarily renounces to its time slot. + * . + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes a thread structure. + * @note This is an internal functions, do not use it in application code. + * + * @param[in] tp pointer to the thread + * @param[in] name thread name + * @param[in] prio the priority level for the new thread + * @return The same thread pointer passed as parameter. + * + * @notapi + */ +thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) { + + tp->prio = prio; + tp->state = CH_STATE_WTSTART; + tp->flags = CH_FLAG_MODE_STATIC; +#if CH_CFG_TIME_QUANTUM > 0 + tp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM; +#endif +#if CH_CFG_USE_MUTEXES == TRUE + tp->realprio = prio; + tp->mtxlist = NULL; +#endif +#if CH_CFG_USE_EVENTS == TRUE + tp->epending = (eventmask_t)0; +#endif +#if CH_DBG_THREADS_PROFILING == TRUE + tp->time = (systime_t)0; +#endif +#if CH_CFG_USE_REGISTRY == TRUE + tp->refs = (trefs_t)1; + tp->name = name; + REG_INSERT(tp); +#else + (void)name; +#endif +#if CH_CFG_USE_WAITEXIT == TRUE + list_init(&tp->waiting); +#endif +#if CH_CFG_USE_MESSAGES == TRUE + queue_init(&tp->msgqueue); +#endif +#if CH_DBG_STATISTICS == TRUE + chTMObjectInit(&tp->stats); +#endif + CH_CFG_THREAD_INIT_HOOK(tp); + return tp; +} + +#if (CH_DBG_FILL_THREADS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Memory fill utility. + * + * @param[in] startp first address to fill + * @param[in] endp last address to fill +1 + * @param[in] v filler value + * + * @notapi + */ +void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) { + + while (startp < endp) { + *startp++ = v; + } +} +#endif /* CH_DBG_FILL_THREADS */ + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized but not inserted in the ready list, + * the initial state is @p CH_STATE_WTSTART. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. + * @post The initialized thread can be subsequently started by invoking + * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() + * depending on the execution context. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * @note Threads created using this function do not obey to the + * @p CH_DBG_FILL_THREADS debug option because it would keep + * the kernel locked for too much time. + * + * @param[out] tdp pointer to the thread descriptor + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @iclass + */ +thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) { + thread_t *tp; + + chDbgCheckClassI(); + chDbgCheck(tdp != NULL); + chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) && + MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) && + (tdp->wend > tdp->wbase) && + (((size_t)tdp->wend - (size_t)tdp->wbase) >= THD_WORKING_AREA_SIZE(0))); + chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL)); + + /* The thread structure is laid out in the upper part of the thread + workspace. The thread position structure is aligned to the required + stack alignment because it represents the stack top.*/ + tp = (thread_t *)((uint8_t *)tdp->wend - + MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN)); + +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) + /* Stack boundary.*/ + tp->wabase = tdp->wbase; +#endif + + /* Setting up the port-dependent part of the working area.*/ + PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg); + + /* The driver object is initialized but not started.*/ + return _thread_init(tp, tdp->name, tdp->prio); +} + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized but not inserted in the ready list, + * the initial state is @p CH_STATE_WTSTART. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. + * @post The initialized thread can be subsequently started by invoking + * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() + * depending on the execution context. + * @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 + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @api + */ +thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp) { + thread_t *tp; + +#if CH_CFG_USE_REGISTRY == TRUE + chDbgAssert(chRegFindThreadByWorkingArea(tdp->wbase) == NULL, + "working area in use"); +#endif + +#if CH_DBG_FILL_THREADS == TRUE + _thread_memfill((uint8_t *)tdp->wbase, + (uint8_t *)tdp->wend, + CH_DBG_STACK_FILL_VALUE); +#endif + + chSysLock(); + tp = chThdCreateSuspendedI(tdp); + chSysUnlock(); + + return tp; +} + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized and make ready to execute. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. + * @post The initialized thread can be subsequently started by invoking + * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() + * depending on the execution context. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * @note Threads created using this function do not obey to the + * @p CH_DBG_FILL_THREADS debug option because it would keep + * the kernel locked for too much time. + * + * @param[out] tdp pointer to the thread descriptor + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @iclass + */ +thread_t *chThdCreateI(const thread_descriptor_t *tdp) { + + return chSchReadyI(chThdCreateSuspendedI(tdp)); +} + +/** + * @brief Creates a new thread into a static memory area. + * @details The new thread is initialized and make ready to execute. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chthdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. + * @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 + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @iclass + */ +thread_t *chThdCreate(const thread_descriptor_t *tdp) { + thread_t *tp; + +#if (CH_CFG_USE_REGISTRY == TRUE) && \ + ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)) + chDbgAssert(chRegFindThreadByWorkingArea(tdp->wbase) == NULL, + "working area in use"); +#endif + +#if CH_DBG_FILL_THREADS == TRUE + _thread_memfill((uint8_t *)tdp->wbase, + (uint8_t *)tdp->wend, + CH_DBG_STACK_FILL_VALUE); +#endif + + chSysLock(); + tp = chThdCreateSuspendedI(tdp); + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + + return tp; +} + +/** + * @brief Creates a new thread into a static memory area. + * @post The created thread has a reference counter set to one, it is + * caller responsibility to call @p chThdRelease() or @p chThdWait() + * in order to release the reference. The thread persists in the + * registry until its reference counter reaches zero. + * @note A thread can terminate by calling @p chThdExit() or by simply + * returning from its main function. + * + * @param[out] wsp pointer to a working area dedicated to the thread stack + * @param[in] size size of the working area + * @param[in] prio the priority level for the new thread + * @param[in] pf the thread function + * @param[in] arg an argument passed to the thread function. It can be + * @p NULL. + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @api + */ +thread_t *chThdCreateStatic(void *wsp, size_t size, + tprio_t prio, tfunc_t pf, void *arg) { + thread_t *tp; + + chDbgCheck((wsp != NULL) && + MEM_IS_ALIGNED(wsp, PORT_WORKING_AREA_ALIGN) && + (size >= THD_WORKING_AREA_SIZE(0)) && + MEM_IS_ALIGNED(size, PORT_STACK_ALIGN) && + (prio <= HIGHPRIO) && (pf != NULL)); + +#if (CH_CFG_USE_REGISTRY == TRUE) && \ + ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)) + chDbgAssert(chRegFindThreadByWorkingArea(wsp) == NULL, + "working area in use"); +#endif + +#if CH_DBG_FILL_THREADS == TRUE + _thread_memfill((uint8_t *)wsp, + (uint8_t *)wsp + size, + CH_DBG_STACK_FILL_VALUE); +#endif + + chSysLock(); + + /* The thread structure is laid out in the upper part of the thread + workspace. The thread position structure is aligned to the required + stack alignment because it represents the stack top.*/ + tp = (thread_t *)((uint8_t *)wsp + size - + MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN)); + +#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) + /* Stack boundary.*/ + tp->wabase = (stkalign_t *)wsp; +#endif + + /* Setting up the port-dependent part of the working area.*/ + PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg); + + tp = _thread_init(tp, "noname", prio); + + /* Starting the thread immediately.*/ + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + + return tp; +} + +/** + * @brief Resumes a thread created with @p chThdCreateI(). + * + * @param[in] tp pointer to the thread + * @return The pointer to the @p thread_t structure allocated for + * the thread into the working space area. + * + * @api + */ +thread_t *chThdStart(thread_t *tp) { + + chSysLock(); + chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state"); + chSchWakeupS(tp, MSG_OK); + chSysUnlock(); + + return tp; +} + +#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) +/** + * @brief Adds a reference to a thread object. + * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in + * order to use this function. + * + * @param[in] tp pointer to the thread + * @return The same thread pointer passed as parameter + * representing the new reference. + * + * @api + */ +thread_t *chThdAddRef(thread_t *tp) { + + chSysLock(); + chDbgAssert(tp->refs < (trefs_t)255, "too many references"); + tp->refs++; + chSysUnlock(); + + return tp; +} + +/** + * @brief Releases a reference to a thread object. + * @details If the references counter reaches zero and the thread + * is in the @p CH_STATE_FINAL state then the thread's memory is + * returned to the proper allocator and the thread is removed + * from the registry.
+ * Threads whose counter reaches zero and are still active become + * "detached" and will be removed from registry on termination. + * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in + * order to use this function. + * @note Static threads are not affected. + * + * @param[in] tp pointer to the thread + * + * @api + */ +void chThdRelease(thread_t *tp) { + + chSysLock(); + chDbgAssert(tp->refs > (trefs_t)0, "not referenced"); + tp->refs--; + + /* If the references counter reaches zero and the thread is in its + terminated state then the memory can be returned to the proper + allocator.*/ + if ((tp->refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) { + REG_REMOVE(tp); + chSysUnlock(); + +#if CH_CFG_USE_DYNAMIC == TRUE + switch (tp->flags & CH_FLAG_MODE_MASK) { +#if CH_CFG_USE_HEAP == TRUE + case CH_FLAG_MODE_HEAP: + chHeapFree(chThdGetWorkingAreaX(tp)); + break; +#endif +#if CH_CFG_USE_MEMPOOLS == TRUE + case CH_FLAG_MODE_MPOOL: + chPoolFree(tp->mpool, chThdGetWorkingAreaX(tp)); + break; +#endif + default: + /* Nothing else to do for static threads.*/ + break; + } +#endif /* CH_CFG_USE_DYNAMIC == TRUE */ + return; + } + chSysUnlock(); +} +#endif /* CH_CFG_USE_REGISTRY == TRUE */ + +/** + * @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 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(); + chThdExitS(msg); + /* The thread never returns here.*/ +} + +/** + * @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 + * + * @sclass + */ +void chThdExitS(msg_t msg) { + thread_t *tp = currp; + + /* Storing exit message.*/ + tp->u.exitcode = msg; + + /* Exit handler hook.*/ + CH_CFG_THREAD_EXIT_HOOK(tp); + +#if CH_CFG_USE_WAITEXIT == TRUE + /* Waking up any waiting thread.*/ + while (list_notempty(&tp->waiting)) { + (void) chSchReadyI(list_remove(&tp->waiting)); + } +#endif + +#if CH_CFG_USE_REGISTRY == TRUE + /* Static threads with no references are immediately removed from the + registry because there is no memory to recover.*/ +#if CH_CFG_USE_DYNAMIC == TRUE + if ((tp->refs == (trefs_t)0) && + ((tp->flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC)) { + REG_REMOVE(tp); + } +#else + if (tp->refs == (trefs_t)0) { + REG_REMOVE(tp); + } +#endif +#endif + + /* Going into final state.*/ + chSchGoSleepS(CH_STATE_FINAL); + + /* The thread never returns here.*/ + chDbgAssert(false, "zombies apocalypse"); +} + +#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Blocks the execution of the invoking thread until the specified + * thread terminates then the exit code is returned. + * @details This function waits for the specified thread to terminate then + * decrements its reference counter, if the counter reaches zero then + * the thread working area is returned to the proper allocator and + * the thread is removed from registry. + * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in + * order to use this function. + * @post Enabling @p chThdWait() requires 2-4 (depending on the + * architecture) extra bytes in the @p thread_t structure. + * @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits + * for the thread termination, no memory allocators are involved. + * + * @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; + + chDbgCheck(tp != NULL); + + chSysLock(); + chDbgAssert(tp != currp, "waiting self"); +#if CH_CFG_USE_REGISTRY == TRUE + chDbgAssert(tp->refs > (trefs_t)0, "no references"); +#endif + + if (tp->state != CH_STATE_FINAL) { + list_insert(currp, &tp->waiting); + chSchGoSleepS(CH_STATE_WTEXIT); + } + msg = tp->u.exitcode; + chSysUnlock(); + +#if CH_CFG_USE_REGISTRY == TRUE + /* Releasing a reference to the thread.*/ + chThdRelease(tp); +#endif + + return msg; +} +#endif /* CH_CFG_USE_WAITEXIT */ + +/** + * @brief Changes the running thread priority level then reschedules if + * necessary. + * @note The function returns the real thread priority regardless of the + * current priority that could be higher than the real priority + * because the priority inheritance mechanism. + * + * @param[in] newprio the new priority level of the running thread + * @return The old priority level. + * + * @api + */ +tprio_t chThdSetPriority(tprio_t newprio) { + tprio_t oldprio; + + chDbgCheck(newprio <= HIGHPRIO); + + chSysLock(); +#if CH_CFG_USE_MUTEXES == TRUE + oldprio = currp->realprio; + if ((currp->prio == currp->realprio) || (newprio > currp->prio)) { + currp->prio = newprio; + } + currp->realprio = newprio; +#else + oldprio = currp->prio; + currp->prio = newprio; +#endif + chSchRescheduleS(); + chSysUnlock(); + + return oldprio; +} + +/** + * @brief Requests a thread termination. + * @pre The target thread must be written to invoke periodically + * @p chThdShouldTerminate() and terminate cleanly if it returns + * @p true. + * @post The specified thread will terminate after detecting the termination + * condition. + * + * @param[in] tp pointer to the thread + * + * @api + */ +void chThdTerminate(thread_t *tp) { + + chSysLock(); + tp->flags |= CH_FLAG_TERMINATE; + chSysUnlock(); +} + +/** + * @brief Suspends the invoking thread for the specified time. + * + * @param[in] time the delay in system ticks, the special values are + * handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * + * @api + */ +void chThdSleep(sysinterval_t time) { + + chSysLock(); + chThdSleepS(time); + chSysUnlock(); +} + +/** + * @brief Suspends the invoking thread until the system time arrives to the + * specified value. + * @note The function has no concept of "past", all specifiable times + * are in the future, this means that if you call this function + * exceeding your calculated intervals then the function will + * return in a far future time, not immediately. + * @see chThdSleepUntilWindowed() + * + * @param[in] time absolute system time + * + * @api + */ +void chThdSleepUntil(systime_t time) { + sysinterval_t interval; + + chSysLock(); + interval = chTimeDiffX(chVTGetSystemTimeX(), time); + if (interval > (sysinterval_t)0) { + chThdSleepS(interval); + } + chSysUnlock(); +} + +/** + * @brief Suspends the invoking thread until the system time arrives to the + * specified value. + * @note The system time is assumed to be between @p prev and @p next + * else the call is assumed to have been called outside the + * allowed time interval, in this case no sleep is performed. + * @see chThdSleepUntil() + * + * @param[in] prev absolute system time of the previous deadline + * @param[in] next absolute system time of the next deadline + * @return the @p next parameter + * + * @api + */ +systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next) { + systime_t time; + + chSysLock(); + time = chVTGetSystemTimeX(); + if (chTimeIsInRangeX(time, prev, next)) { + chThdSleepS(chTimeDiffX(time, next)); + } + chSysUnlock(); + + return next; +} + +/** + * @brief Yields the time slot. + * @details Yields the CPU control to the next thread in the ready list with + * equal priority, if any. + * + * @api + */ +void chThdYield(void) { + + chSysLock(); + chSchDoYieldS(); + chSysUnlock(); +} + +/** + * @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 + * @return The wake up message. + * + * @sclass + */ +msg_t chThdSuspendS(thread_reference_t *trp) { + thread_t *tp = chThdGetSelfX(); + + chDbgAssert(*trp == NULL, "not NULL"); + + *trp = tp; + tp->u.wttrp = trp; + chSchGoSleepS(CH_STATE_SUSPENDED); + + return chThdGetSelfX()->u.rdymsg; +} + +/** + * @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 timeout in system ticks, the special values are + * handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE the thread is not enqueued and + * the function returns @p MSG_TIMEOUT as if a timeout + * occurred. + * . + * @return The wake up message. + * @retval MSG_TIMEOUT if the operation timed out. + * + * @sclass + */ +msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout) { + thread_t *tp = chThdGetSelfX(); + + chDbgAssert(*trp == NULL, "not NULL"); + + if (TIME_IMMEDIATE == timeout) { + return MSG_TIMEOUT; + } + + *trp = tp; + tp->u.wttrp = trp; + + return chSchGoSleepTimeoutS(CH_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_t *tp = *trp; + + chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED"); + + *trp = NULL; + tp->u.rdymsg = msg; + (void) chSchReadyI(tp); + } +} + +/** + * @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 + * + * @iclass + */ +void chThdResumeS(thread_reference_t *trp, msg_t msg) { + + if (*trp != NULL) { + thread_t *tp = *trp; + + chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED"); + + *trp = NULL; + chSchWakeupS(tp, 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 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_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE the thread is not enqueued and + * the function returns @p MSG_TIMEOUT as if a timeout + * occurred. + * . + * @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) { + + if (TIME_IMMEDIATE == timeout) { + return MSG_TIMEOUT; + } + + queue_insert(currp, tqp); + + return chSchGoSleepTimeoutS(CH_STATE_QUEUED, timeout); +} + +/** + * @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) { + + if (queue_notempty(tqp)) { + 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) { + + while (queue_notempty(tqp)) { + chThdDoDequeueNextI(tqp, msg); + } +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chtm.c b/ChibiOS_20.3.2/os/rt/src/chtm.c new file mode 100644 index 0000000..5b3758c --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chtm.c @@ -0,0 +1,168 @@ +/* + 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 rt/src/chtm.c + * @brief Time Measurement module code. + * + * @addtogroup time_measurement + * @details Time Measurement APIs and services. + * @{ + */ + +#include "ch.h" + +#if (CH_CFG_USE_TM == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/** + * @brief Number of iterations in the calibration loop. + * @note This is required in order to assess the best result in + * architectures with instruction cache. + */ +#define TM_CALIBRATION_LOOP 4U + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +static inline void tm_stop(time_measurement_t *tmp, + rtcnt_t now, + rtcnt_t offset) { + + tmp->n++; + tmp->last = (now - tmp->last) - offset; + tmp->cumulative += (rttime_t)tmp->last; + if (tmp->last > tmp->worst) { + tmp->worst = tmp->last; + } + if (tmp->last < tmp->best) { + tmp->best = tmp->last; + } +} + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes the time measurement unit. + * + * @init + */ +void _tm_init(void) { + time_measurement_t tm; + unsigned i; + + /* Time Measurement subsystem calibration, it does a null measurement + and calculates the call overhead which is subtracted to real + measurements.*/ + ch.tm.offset = (rtcnt_t)0; + chTMObjectInit(&tm); + i = TM_CALIBRATION_LOOP; + do { + chTMStartMeasurementX(&tm); + chTMStopMeasurementX(&tm); + i--; + } while (i > 0U); + ch.tm.offset = tm.best; +} + +/** + * @brief Initializes a @p TimeMeasurement object. + * + * @param[out] tmp pointer to a @p TimeMeasurement structure + * + * @init + */ +void chTMObjectInit(time_measurement_t *tmp) { + + tmp->best = (rtcnt_t)-1; + tmp->worst = (rtcnt_t)0; + tmp->last = (rtcnt_t)0; + tmp->n = (ucnt_t)0; + tmp->cumulative = (rttime_t)0; +} + +/** + * @brief Starts a measurement. + * @pre The @p time_measurement_t structure must be initialized. + * + * @param[in,out] tmp pointer to a @p TimeMeasurement structure + * + * @xclass + */ +NOINLINE void chTMStartMeasurementX(time_measurement_t *tmp) { + + tmp->last = chSysGetRealtimeCounterX(); +} + +/** + * @brief Stops a measurement. + * @pre The @p time_measurement_t structure must be initialized. + * + * @param[in,out] tmp pointer to a @p time_measurement_t structure + * + * @xclass + */ +NOINLINE void chTMStopMeasurementX(time_measurement_t *tmp) { + + tm_stop(tmp, chSysGetRealtimeCounterX(), ch.tm.offset); +} + +/** + * @brief Stops a measurement and chains to the next one using the same time + * stamp. + * + * @param[in,out] tmp1 pointer to the @p time_measurement_t structure to be + * stopped + * @param[in,out] tmp2 pointer to the @p time_measurement_t structure to be + * started + * + * + * @xclass + */ +NOINLINE void chTMChainMeasurementToX(time_measurement_t *tmp1, + time_measurement_t *tmp2) { + + /* Starts new measurement.*/ + tmp2->last = chSysGetRealtimeCounterX(); + + /* Stops previous measurement using the same time stamp.*/ + tm_stop(tmp1, tmp2->last, (rtcnt_t)0); +} + +#endif /* CH_CFG_USE_TM == TRUE */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chtrace.c b/ChibiOS_20.3.2/os/rt/src/chtrace.c new file mode 100644 index 0000000..ecc2367 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chtrace.c @@ -0,0 +1,265 @@ +/* + 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 rt/src/chtrace.c + * @brief Tracer code. + * + * @addtogroup trace + * @details System events tracing service. + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) +/** + * @brief Writes a time stamp and increases the trace buffer pointer. + * + * @notapi + */ +NOINLINE static void trace_next(void) { + + ch.dbg.trace_buffer.ptr->time = chVTGetSystemTimeX(); +#if PORT_SUPPORTS_RT == TRUE + ch.dbg.trace_buffer.ptr->rtstamp = chSysGetRealtimeCounterX(); +#else + ch.dbg.trace_buffer.ptr->rtstamp = (rtcnt_t)0; +#endif + + /* Trace hook, useful in order to interface debug tools.*/ + CH_CFG_TRACE_HOOK(ch.dbg.trace_buffer.ptr); + + if (++ch.dbg.trace_buffer.ptr >= + &ch.dbg.trace_buffer.buffer[CH_DBG_TRACE_BUFFER_SIZE]) { + ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0]; + } +} +#endif + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) +/** + * @brief Trace circular buffer subsystem initialization. + * @note Internal use only. + */ +void _trace_init(void) { + unsigned i; + + ch.dbg.trace_buffer.suspended = (uint16_t)~CH_DBG_TRACE_MASK; + ch.dbg.trace_buffer.size = CH_DBG_TRACE_BUFFER_SIZE; + ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0]; + for (i = 0U; i < (unsigned)CH_DBG_TRACE_BUFFER_SIZE; i++) { + ch.dbg.trace_buffer.buffer[i].type = CH_TRACE_TYPE_UNUSED; + } +} + +/** + * @brief Inserts in the circular debug trace buffer a context switch record. + * + * @param[in] ntp the thread being switched in + * @param[in] otp the thread being switched out + * + * @notapi + */ +void _trace_switch(thread_t *ntp, thread_t *otp) { + + (void)ntp; + + if ((ch.dbg.trace_buffer.suspended & CH_DBG_TRACE_MASK_SWITCH) == 0U) { + ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_SWITCH; + ch.dbg.trace_buffer.ptr->state = (uint8_t)otp->state; + ch.dbg.trace_buffer.ptr->u.sw.ntp = currp; + ch.dbg.trace_buffer.ptr->u.sw.wtobjp = otp->u.wtobjp; + trace_next(); + } +} + +/** + * @brief Inserts in the circular debug trace buffer an ISR-enter record. + * + * @param[in] isr name of the isr + * + * @notapi + */ +void _trace_isr_enter(const char *isr) { + + if ((ch.dbg.trace_buffer.suspended & CH_DBG_TRACE_MASK_ISR) == 0U) { + port_lock_from_isr(); + ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_ENTER; + ch.dbg.trace_buffer.ptr->state = 0U; + ch.dbg.trace_buffer.ptr->u.isr.name = isr; + trace_next(); + port_unlock_from_isr(); + } +} + +/** + * @brief Inserts in the circular debug trace buffer an ISR-leave record. + * + * @param[in] isr name of the isr + * + * @notapi + */ +void _trace_isr_leave(const char *isr) { + + if ((ch.dbg.trace_buffer.suspended & CH_DBG_TRACE_MASK_ISR) == 0U) { + port_lock_from_isr(); + ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_LEAVE; + ch.dbg.trace_buffer.ptr->state = 0U; + ch.dbg.trace_buffer.ptr->u.isr.name = isr; + trace_next(); + port_unlock_from_isr(); + } +} + +/** + * @brief Inserts in the circular debug trace buffer an halt record. + * + * @param[in] reason the halt error string + * + * @notapi + */ +void _trace_halt(const char *reason) { + + if ((ch.dbg.trace_buffer.suspended & CH_DBG_TRACE_MASK_HALT) == 0U) { + ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_HALT; + ch.dbg.trace_buffer.ptr->state = 0; + ch.dbg.trace_buffer.ptr->u.halt.reason = reason; + trace_next(); + } +} + +/** + * @brief Adds an user trace record to the trace buffer. + * + * @param[in] up1 user parameter 1 + * @param[in] up2 user parameter 2 + * + * @iclass + */ +void chDbgWriteTraceI(void *up1, void *up2) { + + chDbgCheckClassI(); + + if ((ch.dbg.trace_buffer.suspended & CH_DBG_TRACE_MASK_USER) == 0U) { + ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_USER; + ch.dbg.trace_buffer.ptr->state = 0; + ch.dbg.trace_buffer.ptr->u.user.up1 = up1; + ch.dbg.trace_buffer.ptr->u.user.up2 = up2; + trace_next(); + } +} + +/** + * @brief Adds an user trace record to the trace buffer. + * + * @param[in] up1 user parameter 1 + * @param[in] up2 user parameter 2 + * + * @api + */ +void chDbgWriteTrace(void *up1, void *up2) { + + chSysLock(); + chDbgWriteTraceI(up1, up2); + chSysUnlock(); +} + +/** + * @brief Suspends one or more trace events. + * + * @param[in] mask mask of the trace events to be suspended + * + * @iclass + */ +void chDbgSuspendTraceI(uint16_t mask) { + + chDbgCheckClassI(); + + ch.dbg.trace_buffer.suspended |= mask; +} + +/** + * @brief Suspends one or more trace events. + * + * @param[in] mask mask of the trace events to be suspended + * + * @api + */ +void chDbgSuspendTrace(uint16_t mask) { + + chSysLock(); + chDbgSuspendTraceI(mask); + chSysUnlock(); +} + +/** + * @brief Resumes one or more trace events. + * + * @param[in] mask mask of the trace events to be resumed + * + * @iclass + */ +void chDbgResumeTraceI(uint16_t mask) { + + chDbgCheckClassI(); + + ch.dbg.trace_buffer.suspended &= ~mask; +} + +/** + * @brief Resumes one or more trace events. + * + * @param[in] mask mask of the trace events to be resumed + * + * @api + */ +void chDbgResumeTrace(uint16_t mask) { + + chSysLock(); + chDbgResumeTraceI(mask); + chSysUnlock(); +} +#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/src/chvt.c b/ChibiOS_20.3.2/os/rt/src/chvt.c new file mode 100644 index 0000000..c138796 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/src/chvt.c @@ -0,0 +1,477 @@ +/* + 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 rt/src/chvt.c + * @brief Time and Virtual Timers module code. + * + * @addtogroup time + * @details Time and Virtual Timers related APIs and services. + * @{ + */ + +#include "ch.h" + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/** + * @brief List empty check. + * + * @param[in] vtlp pointer to the list header + * + * @notapi + */ +#define is_vtlist_empty(vtlp) ((vtlp) == (virtual_timers_list_t *)(vtlp)->next) + +/** + * @brief Last timer in the list check. + * + * @param[in] vtlp pointer to the list header + * @param[in] vtp pointer to the timer header + * + * @notapi + */ +#define is_last_timer(vtlp, vtp) ((vtp)->next == (virtual_timer_t *)(vtlp)) + +/** + * @brief Fist timer in the list check. + * + * @param[in] vtlp pointer to the list header + * @param[in] vtp pointer to the timer header + * + * @notapi + */ +#define is_first_timer(vtlp, vtp) ((vtlp)->next == (vtp)) + +/** + * @brief Timer check. + * + * @param[in] vtlp pointer to the list header + * @param[in] vtp pointer to the timer header + * + * @notapi + */ +#define is_timer(vtlp, vtp) ((vtp) != (virtual_timer_t *)(vtlp)) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) +/** + * @brief Delta list compression. + * + * @param[in] vtlp pointer to the delta list to be compressed + * @param[in] deltanow interval to be compacted starting from "lasttime" + * + * @notapi + */ +static void vt_list_compress(virtual_timers_list_t *vtlp, + sysinterval_t deltanow) { + virtual_timer_t *vtp = vtlp->next; + + /* The loop is bounded because the delta list header has the delta field + set to (sysinterval_t)-1 which is larger than all deltas.*/ + while (vtp->delta < deltanow) { + deltanow -= vtp->delta; + vtp->delta = (sysinterval_t)0; + vtp = vtp->next; + } + + vtlp->lasttime = vtlp->lasttime + deltanow; + + /* Adjusting next timer in the list, if any.*/ + if (is_timer(vtlp, vtp)) { + vtp->delta -= deltanow; + } +} +#endif + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Virtual Timers initialization. + * @note Internal use only. + * + * @notapi + */ +void _vt_init(void) { + + ch.vtlist.next = (virtual_timer_t *)&ch.vtlist; + ch.vtlist.prev = (virtual_timer_t *)&ch.vtlist; + ch.vtlist.delta = (sysinterval_t)-1; +#if CH_CFG_ST_TIMEDELTA == 0 + ch.vtlist.systime = (systime_t)0; +#else /* CH_CFG_ST_TIMEDELTA > 0 */ + ch.vtlist.lasttime = (systime_t)0; +#endif /* CH_CFG_ST_TIMEDELTA > 0 */ +} + +/** + * @brief Enables a virtual timer. + * @details The timer is enabled and programmed to trigger after the delay + * specified as parameter. + * @pre The timer must not be already armed before calling this function. + * @note The callback function is invoked from interrupt context. + * + * @param[out] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @iclass + */ +void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + virtual_timers_list_t *vtlp = &ch.vtlist; + virtual_timer_t *p; + sysinterval_t delta; + + chDbgCheckClassI(); + chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); + + vtp->par = par; + vtp->func = vtfunc; + +#if CH_CFG_ST_TIMEDELTA > 0 + { + systime_t now = chVTGetSystemTimeX(); + sysinterval_t deltanow; + + /* If the requested delay is lower than the minimum safe delta then it + is raised to the minimum safe value.*/ + if (delay < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { + delay = (sysinterval_t)CH_CFG_ST_TIMEDELTA; + } + + /* Special case where the timers list is empty.*/ + if (is_vtlist_empty(vtlp)) { + + /* The delta list is empty, the current time becomes the new + delta list base time, the timer is inserted.*/ + vtlp->lasttime = now; + vtlp->next = vtp; + vtlp->prev = vtp; + vtp->next = (virtual_timer_t *)vtlp; + vtp->prev = (virtual_timer_t *)vtlp; + vtp->delta = delay; + +#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION + /* The delta could be too large for the physical timer to handle.*/ + if (delay > (sysinterval_t)TIME_MAX_SYSTIME) { + delay = (sysinterval_t)TIME_MAX_SYSTIME; + } +#endif + + /* Being the first element in the list the alarm timer is started.*/ + port_timer_start_alarm(chTimeAddX(vtlp->lasttime, delay)); + + return; + } + + /* Delay as delta from 'lasttime'. Note, it can overflow and the value + becomes lower than 'deltanow'.*/ + deltanow = chTimeDiffX(vtlp->lasttime, now); + delta = deltanow + delay; + + /* Scenario where a very large delay exceeded the numeric range, it + requires a special handling, the compression procedure.*/ + if (delta < deltanow) { + vt_list_compress(vtlp, deltanow); + delta -= deltanow; + } + else if (delta < vtlp->next->delta) { + sysinterval_t deadline_delta; + + /* A small delay that will become the first element in the delta list + and next deadline.*/ + deadline_delta = delta; +#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION + /* The delta could be too large for the physical timer to handle.*/ + if (deadline_delta > (sysinterval_t)TIME_MAX_SYSTIME) { + deadline_delta = (sysinterval_t)TIME_MAX_SYSTIME; + } +#endif + port_timer_set_alarm(chTimeAddX(vtlp->lasttime, deadline_delta)); + } + } +#else /* CH_CFG_ST_TIMEDELTA == 0 */ + /* Delta is initially equal to the specified delay.*/ + delta = delay; +#endif /* CH_CFG_ST_TIMEDELTA == 0 */ + + /* The delta list is scanned in order to find the correct position for + this timer. */ + p = vtlp->next; + while (p->delta < delta) { + /* Debug assert if the timer is already in the list.*/ + chDbgAssert(p != vtp, "timer already armed"); + + delta -= p->delta; + p = p->next; + } + + /* The timer is inserted in the delta list.*/ + vtp->next = p; + vtp->prev = vtp->next->prev; + vtp->prev->next = vtp; + p->prev = vtp; + vtp->delta = delta; + + /* Calculate new delta for the following entry.*/ + p->delta -= delta; + + /* Special case when the timer is in last position in the list, the + value in the header must be restored.*/ + vtlp->delta = (sysinterval_t)-1; +} + +/** + * @brief Disables a Virtual Timer. + * @pre The timer must be in armed state before calling this function. + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * + * @iclass + */ +void chVTDoResetI(virtual_timer_t *vtp) { + virtual_timers_list_t *vtlp = &ch.vtlist; + + chDbgCheckClassI(); + chDbgCheck(vtp != NULL); + chDbgAssert(vtp->func != NULL, "timer not set or already triggered"); + +#if CH_CFG_ST_TIMEDELTA == 0 + + /* The delta of the timer is added to the next timer.*/ + vtp->next->delta += vtp->delta; + + /* Removing the element from the delta list.*/ + vtp->prev->next = vtp->next; + vtp->next->prev = vtp->prev; + vtp->func = NULL; + + /* The above code changes the value in the header when the removed element + is the last of the list, restoring it.*/ + vtlp->delta = (sysinterval_t)-1; +#else /* CH_CFG_ST_TIMEDELTA > 0 */ + sysinterval_t nowdelta, delta; + + /* If the timer is not the first of the list then it is simply unlinked + else the operation is more complex.*/ + if (!is_first_timer(vtlp, vtp)) { + /* Removing the element from the delta list.*/ + vtp->prev->next = vtp->next; + vtp->next->prev = vtp->prev; + vtp->func = NULL; + + /* Adding delta to the next element, if it is not the last one.*/ + if (is_timer(vtlp, vtp->next)) + vtp->next->delta += vtp->delta; + + return; + } + + /* Removing the first timer from the list.*/ + vtlp->next = vtp->next; + vtlp->next->prev = (virtual_timer_t *)vtlp; + vtp->func = NULL; + + /* If the list become empty then the alarm timer is stopped and done.*/ + if (is_vtlist_empty(vtlp)) { + port_timer_stop_alarm(); + + return; + } + + /* The delta of the removed timer is added to the new first timer.*/ + vtlp->next->delta += vtp->delta; + + /* If the new first timer has a delta of zero then the alarm is not + modified, the already programmed alarm will serve it.*/ +/* if (vtlp->next->delta == 0) { + return; + }*/ + + /* Distance in ticks between the last alarm event and current time.*/ + nowdelta = chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()); + + /* If the current time surpassed the time of the next element in list + then the event interrupt is already pending, just return.*/ + if (nowdelta >= vtlp->next->delta) { + return; + } + + /* Distance from the next scheduled event and now.*/ + delta = vtlp->next->delta - nowdelta; + + /* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA + ticks from now.*/ + if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { + delta = nowdelta + (sysinterval_t)CH_CFG_ST_TIMEDELTA; + } + else { + delta = nowdelta + delta; +#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION + /* The delta could be too large for the physical timer to handle.*/ + if (delta > (sysinterval_t)TIME_MAX_SYSTIME) { + delta = (sysinterval_t)TIME_MAX_SYSTIME; + } +#endif + } + port_timer_set_alarm(chTimeAddX(vtlp->lasttime, delta)); +#endif /* CH_CFG_ST_TIMEDELTA > 0 */ +} + +/** + * @brief Virtual timers ticker. + * @note The system lock is released before entering the callback and + * re-acquired immediately after. It is callback's responsibility + * to acquire the lock if needed. This is done in order to reduce + * interrupts jitter when many timers are in use. + * + * @iclass + */ +void chVTDoTickI(void) { + virtual_timers_list_t *vtlp = &ch.vtlist; + + chDbgCheckClassI(); + +#if CH_CFG_ST_TIMEDELTA == 0 + vtlp->systime++; + if (!is_vtlist_empty(vtlp)) { + /* The list is not empty, processing elements on top.*/ + --vtlp->next->delta; + while (vtlp->next->delta == (sysinterval_t)0) { + virtual_timer_t *vtp; + vtfunc_t fn; + + vtp = vtlp->next; + fn = vtp->func; + vtp->func = NULL; + vtp->next->prev = (virtual_timer_t *)vtlp; + vtlp->next = vtp->next; + chSysUnlockFromISR(); + fn(vtp->par); + chSysLockFromISR(); + } + } +#else /* CH_CFG_ST_TIMEDELTA > 0 */ + virtual_timer_t *vtp; + systime_t now; + sysinterval_t delta, nowdelta; + + /* Looping through timers.*/ + vtp = vtlp->next; + while (true) { + + /* Getting the system time as reference.*/ + now = chVTGetSystemTimeX(); + nowdelta = chTimeDiffX(vtlp->lasttime, now); + + /* The list scan is limited by the timers header having + "vtlp->vt_delta == (sysinterval_t)-1" which is + greater than all deltas.*/ + if (nowdelta < vtp->delta) { + break; + } + + /* Consuming all timers between "vtp->lasttime" and now.*/ + do { + vtfunc_t fn; + + /* The "last time" becomes this timer's expiration time.*/ + vtlp->lasttime += vtp->delta; + nowdelta -= vtp->delta; + + vtp->next->prev = (virtual_timer_t *)vtlp; + vtlp->next = vtp->next; + fn = vtp->func; + vtp->func = NULL; + + /* If the list becomes empty then the timer is stopped.*/ + if (is_vtlist_empty(vtlp)) { + port_timer_stop_alarm(); + } + + /* The callback is invoked outside the kernel critical zone.*/ + chSysUnlockFromISR(); + fn(vtp->par); + chSysLockFromISR(); + + /* Next element in the list.*/ + vtp = vtlp->next; + } + while (vtp->delta <= nowdelta); + } + + /* If the list is empty, nothing else to do.*/ + if (is_vtlist_empty(vtlp)) { + return; + } + + /* The "unprocessed nowdelta" time slice is added to "last time" + and subtracted to next timer's delta.*/ + vtlp->lasttime += nowdelta; + vtlp->next->delta -= nowdelta; + + /* Recalculating the next alarm time.*/ + delta = vtp->delta - chTimeDiffX(vtlp->lasttime, now); + if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { + delta = (sysinterval_t)CH_CFG_ST_TIMEDELTA; + } +#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION + /* The delta could be too large for the physical timer to handle.*/ + else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) { + delta = (sysinterval_t)TIME_MAX_SYSTIME; + } +#endif + port_timer_set_alarm(chTimeAddX(now, delta)); + + chDbgAssert(chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()) <= + chTimeDiffX(vtlp->lasttime, chTimeAddX(now, delta)), + "exceeding delta"); +#endif /* CH_CFG_ST_TIMEDELTA > 0 */ +} + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/templates/chconf.h b/ChibiOS_20.3.2/os/rt/templates/chconf.h new file mode 100644 index 0000000..dd19aae --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/templates/chconf.h @@ -0,0 +1,756 @@ +/* + 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 rt/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 config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_6_1_ + +/*===========================================================================*/ +/** + * @name System timers 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. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 10000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#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 2 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @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 Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#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 Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT 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 + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC 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. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#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) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @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. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS TRUE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS TRUE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK TRUE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS TRUE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() { \ + /* Add threads initialization code here.*/ \ +} + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) { \ + /* Add 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) { \ + /* Add threads finalization code here.*/ \ +} + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* Context switch code here.*/ \ +} + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() { \ + /* IRQ prologue code here.*/ \ +} + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() { \ + /* IRQ epilogue code here.*/ \ +} + +/** + * @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() { \ + /* Idle-enter code here.*/ \ +} + +/** + * @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() { \ + /* Idle-leave code here.*/ \ +} + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() { \ + /* System tick event code here.*/ \ +} + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \ + /* System halt code here.*/ \ +} + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) { \ + /* Trace code here.*/ \ +} + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/templates/meta/module.c b/ChibiOS_20.3.2/os/rt/templates/meta/module.c new file mode 100644 index 0000000..e88687d --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/templates/meta/module.c @@ -0,0 +1,80 @@ +/* + 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 chXxx.c + * @brief XXX module code. + * + * @addtogroup XXX + * @{ + */ + +#include "ch.h" + +#if CH_CFG_USE_XXX || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief XXX Module initialization. + * @note This function is implicitly invoked on system initialization, + * there is no need to explicitly initialize the module. + * + * @notapi + */ +void _xxx_init(void) { + +} + +/** + * @brief Initializes a @p xxx_t object. + * + * @param[out] xxxp pointer to the @p xxx_t object + * + * @init + */ +void chXxxObjectInit(xxx_t *xxxp) { + +} + +#endif /* CH_CFG_USE_XXX */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/rt/templates/meta/module.h b/ChibiOS_20.3.2/os/rt/templates/meta/module.h new file mode 100644 index 0000000..0e120c4 --- /dev/null +++ b/ChibiOS_20.3.2/os/rt/templates/meta/module.h @@ -0,0 +1,76 @@ +/* + 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 chXxx.h + * @brief XXX Module macros and structures. + * + * @addtogroup XXX + * @{ + */ + +#ifndef CHXXX_H +#define CHXXX_H + +#include "ch.h" + +#if CH_CFG_USE_XXX || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void chXxxInit(void); + void chXxxObjectInit(xxx_t *xxxp); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CH_CFG_USE_XXX */ + +#endif /* CHXXX_H */ + +/** @} */ -- cgit v1.2.3