aboutsummaryrefslogtreecommitdiffstats
path: root/ChibiOS_20.3.2/os/rt
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2021-01-22 21:43:36 -0500
committerClyne Sullivan <clyne@bitgloo.com>2021-01-22 21:43:36 -0500
commit48026bb824fd2d9cfb00ecd040db6ef3a416bae9 (patch)
treec14713aedfe78ee8b34f2e1252408782e2e2ff5d /ChibiOS_20.3.2/os/rt
parente080a26651f90c88176140d63a74c93c2f4041a2 (diff)
upload initial port
Diffstat (limited to 'ChibiOS_20.3.2/os/rt')
-rw-r--r--ChibiOS_20.3.2/os/rt/dox/rt.dox152
-rw-r--r--ChibiOS_20.3.2/os/rt/include/ch.h135
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chalign.h120
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chchecks.h263
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chcond.h116
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chdebug.h169
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chdynamic.h99
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chevents.h291
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chmsg.h212
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chmtx.h168
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chregistry.h185
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chrestrictions.h118
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chschd.h716
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chsem.h200
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chstats.h105
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chsys.h469
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chsystypes.h130
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chthreads.h440
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chtime.h492
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chtm.h109
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chtrace.h256
-rw-r--r--ChibiOS_20.3.2/os/rt/include/chvt.h362
-rw-r--r--ChibiOS_20.3.2/os/rt/rt.mk75
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chcond.c321
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chdebug.c257
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chdynamic.c185
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chevents.c603
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chmsg.c221
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chmtx.c537
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chregistry.c268
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chschd.c610
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chsem.c405
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chstats.c126
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chsys.c445
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chthreads.c906
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chtm.c168
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chtrace.c265
-rw-r--r--ChibiOS_20.3.2/os/rt/src/chvt.c477
-rw-r--r--ChibiOS_20.3.2/os/rt/templates/chconf.h756
-rw-r--r--ChibiOS_20.3.2/os/rt/templates/meta/module.c80
-rw-r--r--ChibiOS_20.3.2/os/rt/templates/meta/module.h76
41 files changed, 12088 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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.<br>
+ * It is good practice to invoke this API before invoking any I-class
+ * syscall from an interrupt handler.
+ * @note This API must be invoked exclusively from interrupt handlers.
+ *
+ * @special
+ */
+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.<br>
+ * It is good practice to invoke this API after invoking any I-class
+ * syscall from an interrupt handler.
+ * @note This API must be invoked exclusively from interrupt handlers.
+ *
+ * @special
+ */
+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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+/*
+ 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.
+ * <h2>Operation mode</h2>
+ * 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 <b>must</b> 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 <b>must</b> 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 <b>must</b> 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 <b>must</b> 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+/*
+ 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.
+ * <h2>Operation mode</h2>
+ * Each thread has a mask of pending events inside its
+ * @p thread_t structure.
+ * Operations defined for events:
+ * - <b>Wait</b>, the invoking thread goes to sleep until a certain
+ * AND/OR combination of events are signaled.
+ * - <b>Clear</b>, 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).
+ * - <b>Signal</b>, an events mask is directly ORed to the mask of
+ * the signaled thread.
+ * - <b>Broadcast</b>, each thread registered on an Event Source is
+ * signaled with the events specified in its Event Listener.
+ * - <b>Dispatch</b>, 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.<br>
+ * 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.<br>
+ * 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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rt/src/chmsg.c
+ * @brief Messages code.
+ *
+ * @addtogroup messages
+ * @details Synchronous inter-thread messages APIs and services.
+ * <h2>Operation Mode</h2>
+ * 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.<br>
+ * 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.<br>
+ * 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.<br>
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rt/src/chmtx.c
+ * @brief Mutexes code.
+ *
+ * @addtogroup mutexes
+ * @details Mutexes related APIs and services.
+ * <h2>Operation mode</h2>
+ * 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:
+ * - <b>Lock</b>: 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.
+ * - <b>Unlock</b>: 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.
+ * .
+ * <h2>Constraints</h2>
+ * 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.<br>
+ * Operating under this restriction also ensures that deadlocks
+ * are no possible.
+ *
+ * <h2>Recursive mode</h2>
+ * 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.
+ *
+ * <h2>The priority inversion problem</h2>
+ * The mutexes in ChibiOS/RT implements the <b>full</b> priority
+ * inheritance mechanism in order handle the priority inversion
+ * problem.<br>
+ * 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 <b>must</b> 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 <b>must</b> 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 <b>MUCH MORE</b> 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 <b>MUCH MORE</b> 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rt/src/chregistry.c
+ * @brief Threads registry code.
+ *
+ * @addtogroup registry
+ * @details Threads Registry related APIs and services.
+ * <h2>Operation mode</h2>
+ * The Threads Registry is a double linked list that holds all the
+ * active threads in the system.<br>
+ * Operations defined for the registry:
+ * - <b>First</b>, returns the first, in creation order, active thread
+ * in the system.
+ * - <b>Next</b>, 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.<br>
+ * 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 <string.h>
+
+#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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rt/src/chsem.c
+ * @brief Semaphores code.
+ *
+ * @addtogroup semaphores
+ * @details Semaphores related APIs and services.
+ * <h2>Operation mode</h2>
+ * 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.<br>
+ * Operations defined for semaphores:
+ * - <b>Signal</b>: 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.
+ * - <b>Wait</b>: The semaphore counter is decreased and if the result
+ * becomes negative the thread is queued in the semaphore and
+ * suspended.
+ * - <b>Reset</b>: 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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file rt/src/chthreads.c
+ * @brief Threads code.
+ *
+ * @addtogroup threads
+ * @details Threads related APIs and services.
+ * <h2>Operation mode</h2>
+ * 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.<br>
+ * Operations defined for threads:
+ * - <b>Create</b>, a thread is started on the specified thread
+ * function. This operation is available in multiple variants,
+ * both static and dynamic.
+ * - <b>Exit</b>, 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.
+ * - <b>Wait</b>, a thread waits for the termination of another
+ * thread and retrieves its return value.
+ * - <b>Resume</b>, a thread created in suspended state is started.
+ * - <b>Sleep</b>, the execution of a thread is suspended for the
+ * specified amount of time or the specified future absolute time
+ * is reached.
+ * - <b>SetPriority</b>, a thread changes its own priority level.
+ * - <b>Yield</b>, 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 <b>and</b> 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.<br>
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 */
+
+/** @} */