From 6fc15ee8aa3eea237b19f21e6ca77f45337e11c7 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 4 Jun 2019 08:49:14 +0000 Subject: [PATCH] RT demo using a pre-compiled library and header. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12824 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- demos/various/RT-ARMCM4-USELIB/.cproject | 52 + demos/various/RT-ARMCM4-USELIB/.project | 90 + demos/various/RT-ARMCM4-USELIB/Makefile | 189 ++ ...CM4-USELIB (OpenOCD, Flash and Run).launch | 52 + demos/various/RT-ARMCM4-USELIB/main.c | 93 + demos/various/RT-ARMCM4-USELIB/readme.txt | 18 + demos/various/RT-ARMCM4-USELIB/rt/ch.h | 1629 +++++++++++++++++ demos/various/RT-ARMCM4-USELIB/rt/libch.a | Bin 0 -> 72806 bytes 8 files changed, 2123 insertions(+) create mode 100644 demos/various/RT-ARMCM4-USELIB/.cproject create mode 100644 demos/various/RT-ARMCM4-USELIB/.project create mode 100644 demos/various/RT-ARMCM4-USELIB/Makefile create mode 100644 demos/various/RT-ARMCM4-USELIB/debug/RT-ARMCM4-USELIB (OpenOCD, Flash and Run).launch create mode 100644 demos/various/RT-ARMCM4-USELIB/main.c create mode 100644 demos/various/RT-ARMCM4-USELIB/readme.txt create mode 100644 demos/various/RT-ARMCM4-USELIB/rt/ch.h create mode 100644 demos/various/RT-ARMCM4-USELIB/rt/libch.a diff --git a/demos/various/RT-ARMCM4-USELIB/.cproject b/demos/various/RT-ARMCM4-USELIB/.cproject new file mode 100644 index 000000000..0e1ea4fa7 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/.cproject @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/various/RT-ARMCM4-USELIB/.project b/demos/various/RT-ARMCM4-USELIB/.project new file mode 100644 index 000000000..8b0565da7 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/.project @@ -0,0 +1,90 @@ + + + RT-ARMCM4-USELIB + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + -j1 + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + os + 2 + CHIBIOS/os + + + test + 2 + CHIBIOS/test + + + diff --git a/demos/various/RT-ARMCM4-USELIB/Makefile b/demos/various/RT-ARMCM4-USELIB/Makefile new file mode 100644 index 000000000..c8c006145 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/Makefile @@ -0,0 +1,189 @@ +############################################################################## +# Build global options +# NOTE: Can be overridden externally. +# + +# Compiler options here. +ifeq ($(USE_OPT),) + USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 +endif + +# C specific options here (added to USE_OPT). +ifeq ($(USE_COPT),) + USE_COPT = +endif + +# C++ specific options here (added to USE_OPT). +ifeq ($(USE_CPPOPT),) + USE_CPPOPT = -fno-rtti +endif + +# Enable this if you want the linker to remove unused code and data. +ifeq ($(USE_LINK_GC),) + USE_LINK_GC = yes +endif + +# Linker extra options here. +ifeq ($(USE_LDOPT),) + USE_LDOPT = +endif + +# Enable this if you want link time optimizations (LTO). +ifeq ($(USE_LTO),) + USE_LTO = yes +endif + +# Enable this if you want to see the full log while compiling. +ifeq ($(USE_VERBOSE_COMPILE),) + USE_VERBOSE_COMPILE = no +endif + +# If enabled, this option makes the build process faster by not compiling +# modules not used in the current configuration. +ifeq ($(USE_SMART_BUILD),) + USE_SMART_BUILD = yes +endif + +# +# Build global options +############################################################################## + +############################################################################## +# Architecture or project specific options +# + +# Stack size to be allocated to the Cortex-M process stack. This stack is +# the stack used by the main() thread. +ifeq ($(USE_PROCESS_STACKSIZE),) + USE_PROCESS_STACKSIZE = 0x400 +endif + +# Stack size to the allocated to the Cortex-M main/exceptions stack. This +# stack is used for processing interrupts and exceptions. +ifeq ($(USE_EXCEPTIONS_STACKSIZE),) + USE_EXCEPTIONS_STACKSIZE = 0x400 +endif + +# Enables the use of FPU (no, softfp, hard). +ifeq ($(USE_FPU),) + USE_FPU = no +endif + +# FPU-related options. +ifeq ($(USE_FPU_OPT),) + USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv4-sp-d16 +endif + +# +# Architecture or project specific options +############################################################################## + +############################################################################## +# Project, target, sources and paths +# + +# Define project name here +PROJECT = ch + +# Target settings. +MCU = cortex-m4 + +# Imported source files and paths. +CHIBIOS := ../../.. +CONFDIR := ./cfg +BUILDDIR := ./build +DEPDIR := ./.dep + +# Licensing files. +include $(CHIBIOS)/os/license/license.mk +# Startup files. +include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk +# HAL-OSAL files (optional). +#include $(CHIBIOS)/os/hal/hal.mk +#include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk +#include $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.mk +#include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk +# RTOS files (optional). +#include $(CHIBIOS)/os/rt/rt.mk +#include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk +# Auto-build files in ./source recursively. +include $(CHIBIOS)/tools/mk/autobuild.mk +# Other files (optional). +#include $(CHIBIOS)/test/lib/test.mk +#include $(CHIBIOS)/test/rt/rt_test.mk +#include $(CHIBIOS)/test/oslib/oslib_test.mk + +# Define linker script file here +LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld + +# C sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CSRC = $(ALLCSRC) \ + $(TESTSRC) \ + main.c + +# C++ sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CPPSRC = $(ALLCPPSRC) + +# List ASM source files here. +ASMSRC = $(ALLASMSRC) + +# List ASM with preprocessor source files here. +ASMXSRC = $(ALLXASMSRC) + +# Inclusion directories. +INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC) + +# Define C warning options here. +CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes + +# Define C++ warning options here. +CPPWARN = -Wall -Wextra -Wundef + +# +# Project, target, sources and paths +############################################################################## + +############################################################################## +# Start of user section +# + +# List all user C define here, like -D_DEBUG=1 +UDEFS = -DSTM32F407xx + +# Define ASM defines here +UADEFS = -DSTM32F407xx + +# List all user directories here +UINCDIR = ./rt + +# List the user directory to look for the libraries here +ULIBDIR = ./rt + +# List all user libraries here +ULIBS = -lch + +# +# End of user section +############################################################################## + +############################################################################## +# Common rules +# + +RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk +include $(RULESPATH)/arm-none-eabi.mk +include $(RULESPATH)/rules.mk + +# +# Common rules +############################################################################## + +############################################################################## +# Custom rules +# + +# +# Custom rules +############################################################################## diff --git a/demos/various/RT-ARMCM4-USELIB/debug/RT-ARMCM4-USELIB (OpenOCD, Flash and Run).launch b/demos/various/RT-ARMCM4-USELIB/debug/RT-ARMCM4-USELIB (OpenOCD, Flash and Run).launch new file mode 100644 index 000000000..81ac45316 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/debug/RT-ARMCM4-USELIB (OpenOCD, Flash and Run).launch @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/various/RT-ARMCM4-USELIB/main.c b/demos/various/RT-ARMCM4-USELIB/main.c new file mode 100644 index 000000000..976da585c --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/main.c @@ -0,0 +1,93 @@ +/* + 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. +*/ + +#include "ch.h" + +#if !defined(SYSTEM_CLOCK) +#define SYSTEM_CLOCK 8000000U +#endif + +/* + * @brief System Timer handler. + */ +CH_IRQ_HANDLER(SysTick_Handler) { + + CH_IRQ_PROLOGUE(); + + chSysLockFromISR(); + chSysTimerHandlerI(); + chSysUnlockFromISR(); + + CH_IRQ_EPILOGUE(); +} + +static uint32_t seconds_counter; +static uint32_t minutes_counter; + +/* + * Seconds counter thread. + */ +static THD_WORKING_AREA(waThread1, 128); +static THD_FUNCTION(Thread1, arg) { + + (void)arg; + + chRegSetThreadName("counter"); + + while (true) { + chThdSleepMilliseconds(1000); + seconds_counter++; + } +} + +/* + * Application entry point. + */ +int main(void) { + + /* + * Hardware initialization, in this simple demo just the systick timer is + * initialized. + */ + SysTick->LOAD = SYSTEM_CLOCK / CH_CFG_ST_FREQUENCY - (systime_t)1; + SysTick->VAL = (uint32_t)0; + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk | + SysTick_CTRL_TICKINT_Msk; + + /* IRQ enabled.*/ + NVIC_SetPriority(SysTick_IRQn, 8); + + /* + * System initializations. + * - Kernel initialization, the main() function becomes a thread and the + * RTOS is active. + */ + chSysInit(); + + /* + * Creates the example thread. + */ + (void) chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); + + /* + * Normal main() thread activity, in this demo it does nothing except + * increasing the minutes counter. + */ + while (true) { + chThdSleepSeconds(60); + minutes_counter++; + } +} diff --git a/demos/various/RT-ARMCM4-USELIB/readme.txt b/demos/various/RT-ARMCM4-USELIB/readme.txt new file mode 100644 index 000000000..b7ae04dd8 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/readme.txt @@ -0,0 +1,18 @@ +***************************************************************************** +** ChibiOS/RT port for ARM-Cortex-M4. ** +***************************************************************************** + +** TARGET ** + +The demo targets a generic ARM Cortex-M4 device without HAL support. RT is +included as a library and an header generated by RT-ARMCM4-MAKELIB. + +** The Demo ** + +** Build Procedure ** + +** Notes ** + +The files ch.ld and cmparams.h must be customized for your device. You also +need to provide the CMSIS compliant device header from your vendor, it this +demo an ST header is used. diff --git a/demos/various/RT-ARMCM4-USELIB/rt/ch.h b/demos/various/RT-ARMCM4-USELIB/rt/ch.h new file mode 100644 index 000000000..044cdb262 --- /dev/null +++ b/demos/various/RT-ARMCM4-USELIB/rt/ch.h @@ -0,0 +1,1629 @@ +/* + 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 . +*/ + +#include +#include +#include + +#include "cmparams.h" + +#define CH_H +#define _CHIBIOS_RT_ +#define CH_KERNEL_STABLE 0 +#define CH_KERNEL_VERSION "6.0.0" +#define CH_KERNEL_MAJOR 6 +#define CH_KERNEL_MINOR 0 +#define CH_KERNEL_PATCH 0 +#define FALSE 0 +#define TRUE 1 +#define CHCONF_H +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_6_0_ +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 0 +#define CH_CFG_TIME_QUANTUM 0 +#define CH_CFG_MEMCORE_SIZE 0 +#define CH_CFG_NO_IDLE_THREAD FALSE +#define CH_CFG_OPTIMIZE_SPEED TRUE +#define CH_CFG_USE_TM TRUE +#define CH_CFG_USE_REGISTRY TRUE +#define CH_CFG_USE_WAITEXIT TRUE +#define CH_CFG_USE_SEMAPHORES TRUE +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#define CH_CFG_USE_MUTEXES TRUE +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#define CH_CFG_USE_CONDVARS TRUE +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#define CH_CFG_USE_EVENTS TRUE +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#define CH_CFG_USE_MESSAGES TRUE +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#define CH_CFG_USE_MAILBOXES TRUE +#define CH_CFG_USE_MEMCORE TRUE +#define CH_CFG_USE_HEAP TRUE +#define CH_CFG_USE_MEMPOOLS TRUE +#define CH_CFG_USE_OBJ_FIFOS TRUE +#define CH_CFG_USE_PIPES TRUE +#define CH_CFG_USE_DYNAMIC TRUE +#define CH_CFG_USE_FACTORY TRUE +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#define CH_CFG_FACTORY_MAILBOXES TRUE +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#define CH_CFG_FACTORY_PIPES TRUE +#define CH_DBG_STATISTICS FALSE +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#define CH_DBG_ENABLE_CHECKS FALSE +#define CH_DBG_ENABLE_ASSERTS FALSE +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#define CH_DBG_FILL_THREADS FALSE +#define CH_DBG_THREADS_PROFILING FALSE +#define CH_CFG_SYSTEM_EXTRA_FIELDS +#define CH_CFG_SYSTEM_INIT_HOOK() { } +#define CH_CFG_THREAD_EXTRA_FIELDS +#define CH_CFG_THREAD_INIT_HOOK(tp) { } +#define CH_CFG_THREAD_EXIT_HOOK(tp) { } +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp,otp) { } +#define CH_CFG_IRQ_PROLOGUE_HOOK() { } +#define CH_CFG_IRQ_EPILOGUE_HOOK() { } +#define CH_CFG_IDLE_ENTER_HOOK() { } +#define CH_CFG_IDLE_LEAVE_HOOK() { } +#define CH_CFG_IDLE_LOOP_HOOK() { } +#define CH_CFG_SYSTEM_TICK_HOOK() { } +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { } +#define CH_CFG_TRACE_HOOK(tep) { } +#define CHCHECKS_H +#define CHLICENSE_H +#define CH_FEATURES_BASIC 0 +#define CH_FEATURES_INTERMEDIATE 1 +#define CH_FEATURES_FULL 2 +#define CH_DEPLOY_UNLIMITED -1 +#define CH_DEPLOY_NONE 0 +#define CH_LICENSE_GPL 0 +#define CH_LICENSE_GPL_EXCEPTION 1 +#define CH_LICENSE_COMMERCIAL_FREE 2 +#define CH_LICENSE_COMMERCIAL_DEV_1000 3 +#define CH_LICENSE_COMMERCIAL_DEV_5000 4 +#define CH_LICENSE_COMMERCIAL_FULL 5 +#define CH_LICENSE_COMMERCIAL_RUNTIME 6 +#define CH_LICENSE_PARTNER 7 +#define CHCUSTOMER_H +#define CH_CUSTOMER_ID_STRING "Santa, North Pole" +#define CH_CUSTOMER_ID_CODE "xxxx-yyyy" +#define CH_LICENSE CH_LICENSE_GPL +#define CH_CUSTOMER_LIC_RT TRUE +#define CH_CUSTOMER_LIC_NIL TRUE +#define CH_CUSTOMER_LIC_OSLIB TRUE +#define CH_CUSTOMER_LIC_EX TRUE +#define CH_CUSTOMER_LIC_PORT_CM0 TRUE +#define CH_CUSTOMER_LIC_PORT_CM3 TRUE +#define CH_CUSTOMER_LIC_PORT_CM4 TRUE +#define CH_CUSTOMER_LIC_PORT_CM7 TRUE +#define CH_CUSTOMER_LIC_PORT_ARM79 TRUE +#define CH_CUSTOMER_LIC_PORT_E200Z0 TRUE +#define CH_CUSTOMER_LIC_PORT_E200Z2 TRUE +#define CH_CUSTOMER_LIC_PORT_E200Z3 TRUE +#define CH_CUSTOMER_LIC_PORT_E200Z4 TRUE +#define CH_LICENSE_TYPE_STRING "GNU General Public License 3 (GPL3)" +#define CH_LICENSE_ID_STRING "N/A" +#define CH_LICENSE_ID_CODE "N/A" +#define CH_LICENSE_MODIFIABLE_CODE TRUE +#define CH_LICENSE_FEATURES CH_FEATURES_FULL +#define CH_LICENSE_MAX_DEPLOY CH_DEPLOY_UNLIMITED +#define CHRESTRICTIONS_H + void chSysHalt(const char *reason); +#define CHTYPES_H +typedef uint32_t rtcnt_t; +typedef uint64_t rttime_t; +typedef uint32_t syssts_t; +typedef uint8_t tmode_t; +typedef uint8_t tstate_t; +typedef uint8_t trefs_t; +typedef uint8_t tslices_t; +typedef uint32_t tprio_t; +typedef int32_t msg_t; +typedef int32_t eventid_t; +typedef uint32_t eventmask_t; +typedef uint32_t eventflags_t; +typedef int32_t cnt_t; +typedef uint32_t ucnt_t; +#define ROMCONST const +#define NOINLINE __attribute__((noinline)) +#define PORT_THD_FUNCTION(tname,arg) void tname(void *arg) +#define PACKED_VAR __attribute__((packed)) +#define ALIGNED_VAR(n) __attribute__((aligned(n))) +#define SIZEOF_PTR 4 +#define REVERSE_ORDER 1 +#define CHSYSTYPES_H +typedef struct ch_thread thread_t; +typedef thread_t * thread_reference_t; +typedef struct ch_threads_list threads_list_t; +typedef struct ch_threads_queue threads_queue_t; +typedef struct ch_ready_list ready_list_t; +typedef void (*vtfunc_t)(void *p); +typedef struct ch_virtual_timer virtual_timer_t; +typedef struct ch_virtual_timers_list virtual_timers_list_t; +typedef struct ch_system_debug system_debug_t; +typedef struct ch_system ch_system_t; +#define __CH_STRINGIFY(a) #a +#define CHDEBUG_H +#define CH_DBG_STACK_FILL_VALUE 0x55 +#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() +#define chDbgCheck(c) do { if (CH_DBG_ENABLE_CHECKS != FALSE) { if (!(c)) { chSysHalt(__func__); } } } while (false) +#define chDbgAssert(c,r) do { if (CH_DBG_ENABLE_ASSERTS != FALSE) { if (!(c)) { chSysHalt(__func__); } } } while (false) +#define CHTIME_H +#define TIME_IMMEDIATE ((sysinterval_t)0) +#define TIME_INFINITE ((sysinterval_t)-1) +#define TIME_MAX_INTERVAL ((sysinterval_t)-2) +#define TIME_MAX_SYSTIME ((systime_t)-1) +typedef uint32_t systime_t; +typedef uint32_t sysinterval_t; +typedef uint32_t time_secs_t; +typedef uint32_t time_msecs_t; +typedef uint32_t time_usecs_t; +typedef uint64_t time_conv_t; +#define TIME_S2I(secs) ((sysinterval_t)((time_conv_t)(secs) * (time_conv_t)CH_CFG_ST_FREQUENCY)) +#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)) +#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)) +#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) +#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) +#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) +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; +} +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; +} +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; +} +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; +} +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; +} +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; +} +static inline systime_t chTimeAddX(systime_t systime, + sysinterval_t interval) { + return systime + (systime_t)interval; +} +static inline sysinterval_t chTimeDiffX(systime_t start, systime_t end) { + return (sysinterval_t)((systime_t)(end - start)); +} +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)); +} +#define CHALIGN_H +#define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U) +#define MEM_ALIGN_PREV(p,a) ((size_t)(p) & ~MEM_ALIGN_MASK(a)) +#define MEM_ALIGN_NEXT(p,a) MEM_ALIGN_PREV((size_t)(p) + MEM_ALIGN_MASK(a), (a)) +#define MEM_IS_ALIGNED(p,a) (((size_t)(p) & MEM_ALIGN_MASK(a)) == 0U) +#define MEM_IS_VALID_ALIGNMENT(a) (((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U)) +#define CHCORE_H +#define PORT_ARCHITECTURE_ARM +#define PORT_COMPILER_NAME "GCC " __VERSION__ +#define PORT_USE_ALT_TIMER FALSE +typedef void *regarm_t; +typedef uint64_t stkalign_t; +struct port_context { + struct port_intctx *sp; +}; +#define CORTEX_PRIORITY_LEVELS (1U << CORTEX_PRIORITY_BITS) +#define CORTEX_MINIMUM_PRIORITY (CORTEX_PRIORITY_LEVELS - 1) +#define CORTEX_MAXIMUM_PRIORITY 0U +#define CORTEX_PRIO_MASK(n) ((n) << (8U - (unsigned)CORTEX_PRIORITY_BITS)) +#define PORT_IRQ_IS_VALID_PRIORITY(n) (((n) >= 0U) && ((n) < CORTEX_PRIORITY_LEVELS)) +#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) (((n) >= CORTEX_MAX_KERNEL_PRIORITY) && ((n) < CORTEX_PRIORITY_LEVELS)) +#define MPU_H +#define MPU_TYPE_SEPARATED (1U << 0U) +#define MPU_TYPE_DREGION(n) (((n) >> 8U) & 255U) +#define MPU_TYPE_IREGION(n) (((n) >> 16U) & 255U) +#define MPU_CTRL_ENABLE (1U << 0U) +#define MPU_CTRL_HFNMIENA (1U << 1U) +#define MPU_CTRL_PRIVDEFENA (1U << 2U) +#define MPU_RNR_REGION_MASK (255U << 0U) +#define MPU_RNR_REGION(n) ((n) << 0U) +#define MPU_RBAR_REGION_MASK (15U << 0U) +#define MPU_RBAR_REGION(n) ((n) << 0U) +#define MPU_RBAR_VALID (1U << 4U) +#define MPU_RBAR_ADDR_MASK 0xFFFFFFE0U +#define MPU_RBAR_ADDR(n) ((n) << 5U) +#define MPU_RASR_ENABLE (1U << 0U) +#define MPU_RASR_SIZE_MASK (31U << 1U) +#define MPU_RASR_SIZE(n) ((n) << 1U) +#define MPU_RASR_SIZE_32 MPU_RASR_SIZE(4U) +#define MPU_RASR_SIZE_64 MPU_RASR_SIZE(5U) +#define MPU_RASR_SIZE_128 MPU_RASR_SIZE(6U) +#define MPU_RASR_SIZE_256 MPU_RASR_SIZE(7U) +#define MPU_RASR_SIZE_512 MPU_RASR_SIZE(8U) +#define MPU_RASR_SIZE_1K MPU_RASR_SIZE(9U) +#define MPU_RASR_SIZE_2K MPU_RASR_SIZE(10U) +#define MPU_RASR_SIZE_4K MPU_RASR_SIZE(11U) +#define MPU_RASR_SIZE_8K MPU_RASR_SIZE(12U) +#define MPU_RASR_SIZE_16K MPU_RASR_SIZE(13U) +#define MPU_RASR_SIZE_32K MPU_RASR_SIZE(14U) +#define MPU_RASR_SIZE_64K MPU_RASR_SIZE(15U) +#define MPU_RASR_SIZE_128K MPU_RASR_SIZE(16U) +#define MPU_RASR_SIZE_256K MPU_RASR_SIZE(17U) +#define MPU_RASR_SIZE_512K MPU_RASR_SIZE(18U) +#define MPU_RASR_SIZE_1M MPU_RASR_SIZE(19U) +#define MPU_RASR_SIZE_2M MPU_RASR_SIZE(20U) +#define MPU_RASR_SIZE_4M MPU_RASR_SIZE(21U) +#define MPU_RASR_SIZE_8M MPU_RASR_SIZE(22U) +#define MPU_RASR_SIZE_16M MPU_RASR_SIZE(23U) +#define MPU_RASR_SIZE_32M MPU_RASR_SIZE(24U) +#define MPU_RASR_SIZE_64M MPU_RASR_SIZE(25U) +#define MPU_RASR_SIZE_128M MPU_RASR_SIZE(26U) +#define MPU_RASR_SIZE_256M MPU_RASR_SIZE(27U) +#define MPU_RASR_SIZE_512M MPU_RASR_SIZE(28U) +#define MPU_RASR_SIZE_1G MPU_RASR_SIZE(29U) +#define MPU_RASR_SIZE_2G MPU_RASR_SIZE(30U) +#define MPU_RASR_SIZE_4G MPU_RASR_SIZE(31U) +#define MPU_RASR_SRD_MASK (255U << 8U) +#define MPU_RASR_SRD(n) ((n) << 8U) +#define MPU_RASR_SRD_ALL (0U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB0 (1U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB1 (2U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB2 (4U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB3 (8U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB4 (16U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB5 (32U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB6 (64U << 8U) +#define MPU_RASR_SRD_DISABLE_SUB7 (128U << 8U) +#define MPU_RASR_ATTR_B (1U << 16U) +#define MPU_RASR_ATTR_C (1U << 17U) +#define MPU_RASR_ATTR_S (1U << 18U) +#define MPU_RASR_ATTR_TEX_MASK (7U << 19U) +#define MPU_RASR_ATTR_TEX(n) ((n) << 19U) +#define MPU_RASR_ATTR_AP_MASK (7U << 24U) +#define MPU_RASR_ATTR_AP(n) ((n) << 24U) +#define MPU_RASR_ATTR_AP_NA_NA (0U << 24U) +#define MPU_RASR_ATTR_AP_RW_NA (1U << 24U) +#define MPU_RASR_ATTR_AP_RW_RO (2U << 24U) +#define MPU_RASR_ATTR_AP_RW_RW (3U << 24U) +#define MPU_RASR_ATTR_AP_RO_NA (5U << 24U) +#define MPU_RASR_ATTR_AP_RO_RO (6U << 24U) +#define MPU_RASR_ATTR_XN (1U << 28U) +#define MPU_RASR_ATTR_STRONGLY_ORDERED (MPU_RASR_ATTR_TEX(0)) +#define MPU_RASR_ATTR_SHARED_DEVICE (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_B) +#define MPU_RASR_ATTR_CACHEABLE_WT_NWA (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_CACHEABLE_WB_NWA (MPU_RASR_ATTR_TEX(0) | MPU_RASR_ATTR_B | MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_NON_CACHEABLE (MPU_RASR_ATTR_TEX(1)) +#define MPU_RASR_ATTR_CACHEABLE_WB_WA (MPU_RASR_ATTR_TEX(1) | MPU_RASR_ATTR_B | MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_NON_SHARED_DEVICE (MPU_RASR_ATTR_TEX(2)) +#define MPU_REGION_0 0U +#define MPU_REGION_1 1U +#define MPU_REGION_2 2U +#define MPU_REGION_3 3U +#define MPU_REGION_4 4U +#define MPU_REGION_5 5U +#define MPU_REGION_6 6U +#define MPU_REGION_7 7U +#define mpuEnable(ctrl) { MPU->CTRL = ((uint32_t)ctrl) | MPU_CTRL_ENABLE; SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; } +#define mpuDisable() { SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk; MPU->CTRL = 0; } +#define mpuConfigureRegion(region,addr,attribs) { MPU->RNR = ((uint32_t)region); MPU->RBAR = ((uint32_t)addr); MPU->RASR = ((uint32_t)attribs); } +#define mpuSetRegionAddress(region,addr) { MPU->RNR = ((uint32_t)region); MPU->RBAR = ((uint32_t)addr); } +#define CHCORE_V7M_H +#define PORT_SUPPORTS_RT TRUE +#define PORT_NATURAL_ALIGN sizeof (void *) +#define PORT_STACK_ALIGN sizeof (stkalign_t) +#define PORT_WORKING_AREA_ALIGN (PORT_ENABLE_GUARD_PAGES == TRUE ? 32U : PORT_STACK_ALIGN) +#define CORTEX_BASEPRI_DISABLED 0U +#define PORT_ENABLE_GUARD_PAGES FALSE +#define PORT_USE_MPU_REGION MPU_REGION_7 +#define PORT_IDLE_THREAD_STACK_SIZE 16 +#define PORT_INT_REQUIRED_STACK 64 +#define CORTEX_ENABLE_WFI_IDLE FALSE +#define CORTEX_SIMPLIFIED_PRIORITY FALSE +#define CORTEX_PRIORITY_SVCALL (CORTEX_MAXIMUM_PRIORITY + 1U) +#define CORTEX_PRIGROUP_INIT (7 - CORTEX_PRIORITY_BITS) + #define PORT_GUARD_PAGE_SIZE 0U + #define PORT_ARCHITECTURE_ARM_v7ME + #define PORT_ARCHITECTURE_NAME "ARMv7E-M" + #define PORT_CORE_VARIANT_NAME "Cortex-M4" +#define PORT_INFO "Advanced kernel mode" +#define CORTEX_MAX_KERNEL_PRIORITY (CORTEX_PRIORITY_SVCALL + 1U) +#define CORTEX_BASEPRI_KERNEL CORTEX_PRIO_MASK(CORTEX_MAX_KERNEL_PRIORITY) +#define CORTEX_PRIORITY_PENDSV CORTEX_MAX_KERNEL_PRIORITY +struct port_extctx { + regarm_t r0; + regarm_t r1; + regarm_t r2; + regarm_t r3; + regarm_t r12; + regarm_t lr_thd; + regarm_t pc; + regarm_t xpsr; +}; +struct port_intctx { + regarm_t r4; + regarm_t r5; + regarm_t r6; + regarm_t r7; + regarm_t r8; + regarm_t r9; + regarm_t r10; + regarm_t r11; + regarm_t lr; +}; +#define PORT_SETUP_CONTEXT(tp,wbase,wtop,pf,arg) { (tp)->ctx.sp = (struct port_intctx *)((uint8_t *)(wtop) - sizeof (struct port_intctx)); (tp)->ctx.sp->r4 = (regarm_t)(pf); (tp)->ctx.sp->r5 = (regarm_t)(arg); (tp)->ctx.sp->lr = (regarm_t)_port_thread_start; } +#define PORT_WA_SIZE(n) ((size_t)PORT_GUARD_PAGE_SIZE + sizeof (struct port_intctx) + sizeof (struct port_extctx) + (size_t)(n) + (size_t)PORT_INT_REQUIRED_STACK) +#define PORT_WORKING_AREA(s,n) stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof (stkalign_t)] +#define PORT_IRQ_PROLOGUE() +#define PORT_IRQ_EPILOGUE() _port_irq_epilogue() +#define PORT_IRQ_HANDLER(id) void id(void) +#define PORT_FAST_IRQ_HANDLER(id) void id(void) +#define port_switch(ntp,otp) _port_switch(ntp, otp) + void _port_irq_epilogue(void); + void _port_switch(thread_t *ntp, thread_t *otp); + void _port_thread_start(void); + void _port_switch_from_isr(void); + void _port_exit_from_isr(void); +static inline void port_init(void) { + NVIC_SetPriorityGrouping(CORTEX_PRIGROUP_INIT); + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + NVIC_SetPriority(SVCall_IRQn, CORTEX_PRIORITY_SVCALL); + NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV); +} +static inline syssts_t port_get_irq_status(void) { + syssts_t sts; + sts = (syssts_t)__get_BASEPRI(); + return sts; +} +static inline bool port_irq_enabled(syssts_t sts) { + return sts == (syssts_t)CORTEX_BASEPRI_DISABLED; +} +static inline bool port_is_isr_context(void) { + return (bool)((__get_IPSR() & 0x1FFU) != 0U); +} +static inline void port_lock(void) { + __set_BASEPRI(CORTEX_BASEPRI_KERNEL); +} +static inline void port_unlock(void) { + __set_BASEPRI(CORTEX_BASEPRI_DISABLED); +} +static inline void port_lock_from_isr(void) { + port_lock(); +} +static inline void port_unlock_from_isr(void) { + port_unlock(); +} +static inline void port_disable(void) { + __disable_irq(); +} +static inline void port_suspend(void) { + __set_BASEPRI(CORTEX_BASEPRI_KERNEL); + __enable_irq(); +} +static inline void port_enable(void) { + __set_BASEPRI(CORTEX_BASEPRI_DISABLED); + __enable_irq(); +} +static inline void port_wait_for_interrupt(void) { +} +static inline rtcnt_t port_rt_get_counter_value(void) { + return DWT->CYCCNT; +} +#define CHTRACE_H +#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 +#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) +#define _trace_init() +#define _trace_switch(ntp,otp) +#define _trace_isr_enter(isr) +#define _trace_isr_leave(isr) +#define _trace_halt(reason) +#define chDbgWriteTraceI(up1,up2) +#define chDbgWriteTrace(up1,up2) +#define CHTM_H +typedef struct { + rtcnt_t offset; +} tm_calibration_t; +typedef struct { + rtcnt_t best; + rtcnt_t worst; + rtcnt_t last; + ucnt_t n; + rttime_t cumulative; +} time_measurement_t; + 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); +#define CHSTATS_H +#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() +#define CHSCHD_H +#define MSG_OK (msg_t)0 +#define MSG_TIMEOUT (msg_t)-1 +#define MSG_RESET (msg_t)-2 +#define NOPRIO (tprio_t)0 +#define IDLEPRIO (tprio_t)1 +#define LOWPRIO (tprio_t)2 +#define NORMALPRIO (tprio_t)128 +#define HIGHPRIO (tprio_t)255 +#define CH_STATE_READY (tstate_t)0 +#define CH_STATE_CURRENT (tstate_t)1 +#define CH_STATE_WTSTART (tstate_t)2 +#define CH_STATE_SUSPENDED (tstate_t)3 +#define CH_STATE_QUEUED (tstate_t)4 +#define CH_STATE_WTSEM (tstate_t)5 +#define CH_STATE_WTMTX (tstate_t)6 +#define CH_STATE_WTCOND (tstate_t)7 +#define CH_STATE_SLEEPING (tstate_t)8 +#define CH_STATE_WTEXIT (tstate_t)9 +#define CH_STATE_WTOREVT (tstate_t)10 +#define CH_STATE_WTANDEVT (tstate_t)11 +#define CH_STATE_SNDMSGQ (tstate_t)12 +#define CH_STATE_SNDMSG (tstate_t)13 +#define CH_STATE_WTMSG (tstate_t)14 +#define CH_STATE_FINAL (tstate_t)15 +#define CH_STATE_NAMES "READY", "CURRENT", "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL" +#define CH_FLAG_MODE_MASK (tmode_t)3U +#define CH_FLAG_MODE_STATIC (tmode_t)0U +#define CH_FLAG_MODE_HEAP (tmode_t)1U +#define CH_FLAG_MODE_MPOOL (tmode_t)2U +#define CH_FLAG_TERMINATE (tmode_t)4U +struct ch_threads_list { + thread_t *next; +}; +struct ch_threads_queue { + thread_t *next; + thread_t *prev; +}; +struct ch_thread { + threads_queue_t queue; + tprio_t prio; + struct port_context ctx; + thread_t *newer; + thread_t *older; + const char *name; + stkalign_t *wabase; + tstate_t state; + tmode_t flags; + trefs_t refs; + union { + msg_t rdymsg; + msg_t exitcode; + void *wtobjp; + thread_reference_t *wttrp; + msg_t sentmsg; + struct ch_semaphore *wtsemp; + struct ch_mutex *wtmtxp; + eventmask_t ewmask; + } u; + threads_list_t waiting; + threads_queue_t msgqueue; + eventmask_t epending; + struct ch_mutex *mtxlist; + tprio_t realprio; + void *mpool; + CH_CFG_THREAD_EXTRA_FIELDS +}; +struct ch_virtual_timer { + virtual_timer_t *next; + virtual_timer_t *prev; + sysinterval_t delta; + vtfunc_t func; + void *par; +}; +struct ch_virtual_timers_list { + virtual_timer_t *next; + virtual_timer_t *prev; + sysinterval_t delta; + volatile systime_t systime; +}; +struct ch_ready_list { + threads_queue_t queue; + tprio_t prio; + struct port_context ctx; + thread_t *newer; + thread_t *older; + thread_t *current; +}; +struct ch_system_debug { + const char * volatile panic_msg; +}; +struct ch_system { + ready_list_t rlist; + virtual_timers_list_t vtlist; + system_debug_t dbg; + thread_t mainthread; + tm_calibration_t tm; + CH_CFG_SYSTEM_EXTRA_FIELDS +}; +#define firstprio(rlp) ((rlp)->next->prio) +#define currp ch.rlist.current +extern ch_system_t ch; + 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); +static inline void list_init(threads_list_t *tlp) { + tlp->next = (thread_t *)tlp; +} +static inline bool list_isempty(threads_list_t *tlp) { + return (bool)(tlp->next == (thread_t *)tlp); +} +static inline bool list_notempty(threads_list_t *tlp) { + return (bool)(tlp->next != (thread_t *)tlp); +} +static inline void queue_init(threads_queue_t *tqp) { + tqp->next = (thread_t *)tqp; + tqp->prev = (thread_t *)tqp; +} +static inline bool queue_isempty(const threads_queue_t *tqp) { + return (bool)(tqp->next == (const thread_t *)tqp); +} +static inline bool queue_notempty(const threads_queue_t *tqp) { + return (bool)(tqp->next != (const thread_t *)tqp); +} +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; +} +static inline bool chSchIsRescRequiredI(void) { + chDbgCheckClassI(); + return firstprio(&ch.rlist.queue) > currp->prio; +} +static inline bool chSchCanYieldS(void) { + chDbgCheckClassS(); + return firstprio(&ch.rlist.queue) >= currp->prio; +} +static inline void chSchDoYieldS(void) { + chDbgCheckClassS(); + if (chSchCanYieldS()) { + chSchDoRescheduleBehind(); + } +} +static inline void chSchPreemption(void) { + tprio_t p1 = firstprio(&ch.rlist.queue); + tprio_t p2 = currp->prio; + if (p1 > p2) { + chSchDoRescheduleAhead(); + } +} +#define CHSYS_H +#define CH_INTEGRITY_RLIST 1U +#define CH_INTEGRITY_VTLIST 2U +#define CH_INTEGRITY_REGISTRY 4U +#define CH_INTEGRITY_PORT 8U +#define CH_IRQ_IS_VALID_PRIORITY(prio) PORT_IRQ_IS_VALID_PRIORITY(prio) +#define CH_IRQ_IS_VALID_KERNEL_PRIORITY(prio) PORT_IRQ_IS_VALID_KERNEL_PRIORITY(prio) +#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE(); CH_CFG_IRQ_PROLOGUE_HOOK(); _stats_increase_irq(); _trace_isr_enter(__func__); _dbg_check_enter_isr() +#define CH_IRQ_EPILOGUE() _dbg_check_leave_isr(); _trace_isr_leave(__func__); CH_CFG_IRQ_EPILOGUE_HOOK(); PORT_IRQ_EPILOGUE() +#define CH_IRQ_HANDLER(id) PORT_IRQ_HANDLER(id) +#define CH_FAST_IRQ_HANDLER(id) PORT_FAST_IRQ_HANDLER(id) +#define S2RTC(freq,sec) ((freq) * (sec)) +#define MS2RTC(freq,msec) (rtcnt_t)((((freq) + 999UL) / 1000UL) * (msec)) +#define US2RTC(freq,usec) (rtcnt_t)((((freq) + 999999UL) / 1000000UL) * (usec)) +#define RTC2S(freq,n) ((((n) - 1UL) / (freq)) + 1UL) +#define RTC2MS(freq,n) ((((n) - 1UL) / ((freq) / 1000UL)) + 1UL) +#define RTC2US(freq,n) ((((n) - 1UL) / ((freq) / 1000000UL)) + 1UL) +#define chSysGetRealtimeCounterX() (rtcnt_t)port_rt_get_counter_value() +#define chSysSwitch(ntp,otp) { _trace_switch(ntp, otp); _stats_ctxswc(ntp, otp); CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp); port_switch(ntp, otp); } +extern stkalign_t ch_idle_thread_wa[]; + void chSysInit(void); + bool chSysIntegrityCheckI(unsigned testmask); + void chSysTimerHandlerI(void); + syssts_t chSysGetStatusAndLockX(void); + void chSysRestoreStatusX(syssts_t sts); + bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end); + void chSysPolledDelayX(rtcnt_t cycles); +static inline void chSysDisable(void) { + port_disable(); + _dbg_check_disable(); +} +static inline void chSysSuspend(void) { + port_suspend(); + _dbg_check_suspend(); +} +static inline void chSysEnable(void) { + _dbg_check_enable(); + port_enable(); +} +static inline void chSysLock(void) { + port_lock(); + _stats_start_measure_crit_thd(); + _dbg_check_lock(); +} +static inline void chSysUnlock(void) { + _dbg_check_unlock(); + _stats_stop_measure_crit_thd(); + chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) || + (ch.rlist.current->prio >= ch.rlist.queue.next->prio), + "priority order violation"); + port_unlock(); +} +static inline void chSysLockFromISR(void) { + port_lock_from_isr(); + _stats_start_measure_crit_isr(); + _dbg_check_lock_from_isr(); +} +static inline void chSysUnlockFromISR(void) { + _dbg_check_unlock_from_isr(); + _stats_stop_measure_crit_isr(); + port_unlock_from_isr(); +} +static inline void chSysUnconditionalLock(void) { + if (port_irq_enabled(port_get_irq_status())) { + chSysLock(); + } +} +static inline void chSysUnconditionalUnlock(void) { + if (!port_irq_enabled(port_get_irq_status())) { + chSysUnlock(); + } +} +static inline thread_t *chSysGetIdleThreadX(void) { + return ch.rlist.queue.prev; +} +#define CHVT_H + void _vt_init(void); + void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par); + void chVTDoResetI(virtual_timer_t *vtp); +static inline void chVTObjectInit(virtual_timer_t *vtp) { + vtp->func = NULL; +} +static inline systime_t chVTGetSystemTimeX(void) { + return ch.vtlist.systime; +} +static inline systime_t chVTGetSystemTime(void) { + systime_t systime; + chSysLock(); + systime = chVTGetSystemTimeX(); + chSysUnlock(); + return systime; +} +static inline sysinterval_t chVTTimeElapsedSinceX(systime_t start) { + return chTimeDiffX(start, chVTGetSystemTimeX()); +} +static inline bool chVTIsSystemTimeWithinX(systime_t start, systime_t end) { + return chTimeIsInRangeX(chVTGetSystemTimeX(), start, end); +} +static inline bool chVTIsSystemTimeWithin(systime_t start, systime_t end) { + return chTimeIsInRangeX(chVTGetSystemTime(), start, end); +} +static inline bool chVTGetTimersStateI(sysinterval_t *timep) { + chDbgCheckClassI(); + if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) { + return false; + } + if (timep != NULL) { + *timep = ch.vtlist.next->delta; + } + return true; +} +static inline bool chVTIsArmedI(const virtual_timer_t *vtp) { + chDbgCheckClassI(); + return (bool)(vtp->func != NULL); +} +static inline bool chVTIsArmed(const virtual_timer_t *vtp) { + bool b; + chSysLock(); + b = chVTIsArmedI(vtp); + chSysUnlock(); + return b; +} +static inline void chVTResetI(virtual_timer_t *vtp) { + if (chVTIsArmedI(vtp)) { + chVTDoResetI(vtp); + } +} +static inline void chVTReset(virtual_timer_t *vtp) { + chSysLock(); + chVTResetI(vtp); + chSysUnlock(); +} +static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + chVTResetI(vtp); + chVTDoSetI(vtp, delay, vtfunc, par); +} +static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + chSysLock(); + chVTSetI(vtp, delay, vtfunc, par); + chSysUnlock(); +} +static inline void chVTDoTickI(void) { + chDbgCheckClassI(); + ch.vtlist.systime++; + if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.next) { + --ch.vtlist.next->delta; + while (ch.vtlist.next->delta == (sysinterval_t)0) { + virtual_timer_t *vtp; + vtfunc_t fn; + vtp = ch.vtlist.next; + fn = vtp->func; + vtp->func = NULL; + vtp->next->prev = (virtual_timer_t *)&ch.vtlist; + ch.vtlist.next = vtp->next; + chSysUnlockFromISR(); + fn(vtp->par); + chSysLockFromISR(); + } + } +} +#define CHTHREADS_H +typedef void (*tfunc_t)(void *p); +typedef struct { + const char *name; + stkalign_t *wbase; + stkalign_t *wend; + tprio_t prio; + tfunc_t funcp; + void *arg; +} thread_descriptor_t; +#define _THREADS_QUEUE_DATA(name) {(thread_t *)&name, (thread_t *)&name} +#define _THREADS_QUEUE_DECL(name) threads_queue_t name = _THREADS_QUEUE_DATA(name) +#define THD_WORKING_AREA_SIZE(n) MEM_ALIGN_NEXT(sizeof(thread_t) + PORT_WA_SIZE(n), PORT_STACK_ALIGN) +#define THD_WORKING_AREA(s,n) PORT_WORKING_AREA(s, n) +#define THD_WORKING_AREA_BASE(s) ((stkalign_t *)(s)) +#define THD_WORKING_AREA_END(s) (THD_WORKING_AREA_BASE(s) + (sizeof (s) / sizeof (stkalign_t))) +#define THD_FUNCTION(tname,arg) PORT_THD_FUNCTION(tname, arg) +#define chThdSleepSeconds(sec) chThdSleep(TIME_S2I(sec)) +#define chThdSleepMilliseconds(msec) chThdSleep(TIME_MS2I(msec)) +#define chThdSleepMicroseconds(usec) chThdSleep(TIME_US2I(usec)) + thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio); + 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); + thread_t *chThdAddRef(thread_t *tp); + void chThdRelease(thread_t *tp); + void chThdExit(msg_t msg); + void chThdExitS(msg_t msg); + msg_t chThdWait(thread_t *tp); + 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); +static inline thread_t *chThdGetSelfX(void) { + return ch.rlist.current; +} +static inline tprio_t chThdGetPriorityX(void) { + return chThdGetSelfX()->prio; +} +static inline stkalign_t *chThdGetWorkingAreaX(thread_t *tp) { + return tp->wabase; +} +static inline bool chThdTerminatedX(thread_t *tp) { + return (bool)(tp->state == CH_STATE_FINAL); +} +static inline bool chThdShouldTerminateX(void) { + return (bool)((chThdGetSelfX()->flags & CH_FLAG_TERMINATE) != (tmode_t)0); +} +static inline thread_t *chThdStartI(thread_t *tp) { + chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state"); + return chSchReadyI(tp); +} +static inline void chThdSleepS(sysinterval_t ticks) { + chDbgCheck(ticks != TIME_IMMEDIATE); + (void) chSchGoSleepTimeoutS(CH_STATE_SLEEPING, ticks); +} +static inline void chThdQueueObjectInit(threads_queue_t *tqp) { + queue_init(tqp); +} +static inline bool chThdQueueIsEmptyI(threads_queue_t *tqp) { + chDbgCheckClassI(); + return queue_isempty(tqp); +} +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); +} +#define CHREGISTRY_H +typedef struct { + char identifier[4]; + uint8_t zero; + uint8_t size; + uint16_t version; + uint8_t ptrsize; + uint8_t timesize; + uint8_t threadsize; + uint8_t off_prio; + uint8_t off_ctx; + uint8_t off_newer; + uint8_t off_older; + uint8_t off_name; + uint8_t off_stklimit; + uint8_t off_state; + uint8_t off_flags; + uint8_t off_refs; + uint8_t off_preempt; + uint8_t off_time; +} chdebug_t; +#define REG_REMOVE(tp) { (tp)->older->newer = (tp)->newer; (tp)->newer->older = (tp)->older; } +#define REG_INSERT(tp) { (tp)->newer = (thread_t *)&ch.rlist; (tp)->older = ch.rlist.older; (tp)->older->newer = (tp); ch.rlist.older = (tp); } + 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); +static inline void chRegSetThreadName(const char *name) { + ch.rlist.current->name = name; +} +static inline const char *chRegGetThreadNameX(thread_t *tp) { + return tp->name; +} +static inline void chRegSetThreadNameX(thread_t *tp, const char *name) { + tp->name = name; +} +#define CHSEM_H +typedef struct ch_semaphore { + threads_queue_t queue; + cnt_t cnt; +} semaphore_t; +#define _SEMAPHORE_DATA(name,n) {_THREADS_QUEUE_DATA(name.queue), n} +#define SEMAPHORE_DECL(name,n) semaphore_t name = _SEMAPHORE_DATA(name, n) + void chSemObjectInit(semaphore_t *sp, cnt_t n); + void chSemReset(semaphore_t *sp, cnt_t n); + void chSemResetI(semaphore_t *sp, cnt_t n); + 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); +static inline void chSemFastWaitI(semaphore_t *sp) { + chDbgCheckClassI(); + sp->cnt--; +} +static inline void chSemFastSignalI(semaphore_t *sp) { + chDbgCheckClassI(); + sp->cnt++; +} +static inline cnt_t chSemGetCounterI(const semaphore_t *sp) { + chDbgCheckClassI(); + return sp->cnt; +} +#define CHMTX_H +typedef struct ch_mutex mutex_t; +struct ch_mutex { + threads_queue_t queue; + thread_t *owner; + mutex_t *next; +}; +#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL} +#define MUTEX_DECL(name) mutex_t name = _MUTEX_DATA(name) + 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); +static inline bool chMtxQueueNotEmptyS(mutex_t *mp) { + chDbgCheckClassS(); + return queue_notempty(&mp->queue); +} +static inline thread_t *chMtxGetOwnerI(mutex_t *mp) { + chDbgCheckClassI(); + return mp->owner; +} +static inline mutex_t *chMtxGetNextMutexX(void) { + return chThdGetSelfX()->mtxlist; +} +#define CHCOND_H +typedef struct condition_variable { + threads_queue_t queue; +} condition_variable_t; +#define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.queue)} +#define CONDVAR_DECL(name) condition_variable_t name = _CONDVAR_DATA(name) + 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); + msg_t chCondWaitTimeout(condition_variable_t *cp, sysinterval_t timeout); + msg_t chCondWaitTimeoutS(condition_variable_t *cp, sysinterval_t timeout); +#define CHEVENTS_H +typedef struct event_listener event_listener_t; +struct event_listener { + event_listener_t *next; + thread_t *listener; + eventmask_t events; + eventflags_t flags; + eventflags_t wflags; +}; +typedef struct event_source { + event_listener_t *next; +} event_source_t; +typedef void (*evhandler_t)(eventid_t id); +#define ALL_EVENTS ((eventmask_t)-1) +#define EVENT_MASK(eid) ((eventmask_t)1 << (eventmask_t)(eid)) +#define _EVENTSOURCE_DATA(name) {(event_listener_t *)(&name)} +#define EVENTSOURCE_DECL(name) event_source_t name = _EVENTSOURCE_DATA(name) + void chEvtRegisterMaskWithFlags(event_source_t *esp, + event_listener_t *elp, + eventmask_t events, + eventflags_t wflags); + void chEvtUnregister(event_source_t *esp, event_listener_t *elp); + eventmask_t chEvtGetAndClearEventsI(eventmask_t events); + eventmask_t chEvtGetAndClearEvents(eventmask_t events); + eventmask_t chEvtAddEvents(eventmask_t events); + eventflags_t chEvtGetAndClearFlags(event_listener_t *elp); + eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp); + void chEvtSignal(thread_t *tp, eventmask_t events); + void chEvtSignalI(thread_t *tp, eventmask_t events); + void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags); + void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags); + void chEvtDispatch(const evhandler_t *handlers, eventmask_t events); + eventmask_t chEvtWaitOne(eventmask_t events); + eventmask_t chEvtWaitAny(eventmask_t events); + eventmask_t chEvtWaitAll(eventmask_t events); + 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); +static inline void chEvtObjectInit(event_source_t *esp) { + esp->next = (event_listener_t *)esp; +} +static inline void chEvtRegisterMask(event_source_t *esp, + event_listener_t *elp, + eventmask_t events) { + chEvtRegisterMaskWithFlags(esp, elp, events, (eventflags_t)-1); +} +static inline void chEvtRegister(event_source_t *esp, + event_listener_t *elp, + eventid_t event) { + chEvtRegisterMask(esp, elp, EVENT_MASK(event)); +} +static inline bool chEvtIsListeningI(event_source_t *esp) { + return (bool)(esp != (event_source_t *)esp->next); +} +static inline void chEvtBroadcast(event_source_t *esp) { + chEvtBroadcastFlags(esp, (eventflags_t)0); +} +static inline void chEvtBroadcastI(event_source_t *esp) { + chEvtBroadcastFlagsI(esp, (eventflags_t)0); +} +static inline eventmask_t chEvtAddEventsI(eventmask_t events) { + return currp->epending |= events; +} +static inline eventmask_t chEvtGetEventsX(void) { + return currp->epending; +} +#define CHMSG_H + msg_t chMsgSend(thread_t *tp, msg_t msg); + thread_t * chMsgWait(void); + void chMsgRelease(thread_t *tp, msg_t msg); +static inline bool chMsgIsPendingI(thread_t *tp) { + chDbgCheckClassI(); + return (bool)(tp->msgqueue.next != (thread_t *)&tp->msgqueue); +} +static inline msg_t chMsgGet(thread_t *tp) { + chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state"); + return tp->u.sentmsg; +} +static inline void chMsgReleaseS(thread_t *tp, msg_t msg) { + chDbgCheckClassS(); + chSchWakeupS(tp, msg); +} +#define CHLIB_H +#define _CHIBIOS_OSLIB_ +#define CH_OSLIB_STABLE 0 +#define CH_OSLIB_VERSION "1.1.0" +#define CH_OSLIB_MAJOR 1 +#define CH_OSLIB_MINOR 1 +#define CH_OSLIB_PATCH 0 +#define CHBSEM_H +typedef struct ch_binary_semaphore { + semaphore_t sem; +} binary_semaphore_t; +#define _BSEMAPHORE_DATA(name,taken) {_SEMAPHORE_DATA(name.sem, ((taken) ? 0 : 1))} +#define BSEMAPHORE_DECL(name,taken) binary_semaphore_t name = _BSEMAPHORE_DATA(name, taken) +static inline void chBSemObjectInit(binary_semaphore_t *bsp, bool taken) { + chSemObjectInit(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); +} +static inline msg_t chBSemWait(binary_semaphore_t *bsp) { + return chSemWait(&bsp->sem); +} +static inline msg_t chBSemWaitS(binary_semaphore_t *bsp) { + chDbgCheckClassS(); + return chSemWaitS(&bsp->sem); +} +static inline msg_t chBSemWaitTimeoutS(binary_semaphore_t *bsp, + sysinterval_t timeout) { + chDbgCheckClassS(); + return chSemWaitTimeoutS(&bsp->sem, timeout); +} +static inline msg_t chBSemWaitTimeout(binary_semaphore_t *bsp, + sysinterval_t timeout) { + return chSemWaitTimeout(&bsp->sem, timeout); +} +static inline void chBSemResetI(binary_semaphore_t *bsp, bool taken) { + chDbgCheckClassI(); + chSemResetI(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); +} +static inline void chBSemReset(binary_semaphore_t *bsp, bool taken) { + chSemReset(&bsp->sem, taken ? (cnt_t)0 : (cnt_t)1); +} +static inline void chBSemSignalI(binary_semaphore_t *bsp) { + chDbgCheckClassI(); + if (bsp->sem.cnt < (cnt_t)1) { + chSemSignalI(&bsp->sem); + } +} +static inline void chBSemSignal(binary_semaphore_t *bsp) { + chSysLock(); + chBSemSignalI(bsp); + chSchRescheduleS(); + chSysUnlock(); +} +static inline bool chBSemGetStateI(const binary_semaphore_t *bsp) { + chDbgCheckClassI(); + return (bsp->sem.cnt > (cnt_t)0) ? false : true; +} +#define CHMBOXES_H +typedef struct { + msg_t *buffer; + msg_t *top; + msg_t *wrptr; + msg_t *rdptr; + size_t cnt; + bool reset; + threads_queue_t qw; + threads_queue_t qr; +} mailbox_t; +#define _MAILBOX_DATA(name,buffer,size) { (msg_t *)(buffer), (msg_t *)(buffer) + size, (msg_t *)(buffer), (msg_t *)(buffer), (size_t)0, false, _THREADS_QUEUE_DATA(name.qw), _THREADS_QUEUE_DATA(name.qr), } +#define MAILBOX_DECL(name,buffer,size) mailbox_t name = _MAILBOX_DATA(name, buffer, size) + void chMBObjectInit(mailbox_t *mbp, msg_t *buf, size_t n); + void chMBReset(mailbox_t *mbp); + void chMBResetI(mailbox_t *mbp); + msg_t chMBPostTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout); + msg_t chMBPostTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout); + msg_t chMBPostI(mailbox_t *mbp, msg_t msg); + msg_t chMBPostAheadTimeout(mailbox_t *mbp, msg_t msg, sysinterval_t timeout); + msg_t chMBPostAheadTimeoutS(mailbox_t *mbp, msg_t msg, sysinterval_t timeout); + msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg); + msg_t chMBFetchTimeout(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout); + msg_t chMBFetchTimeoutS(mailbox_t *mbp, msg_t *msgp, sysinterval_t timeout); + msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp); +static inline size_t chMBGetSizeI(const mailbox_t *mbp) { + return (size_t)(mbp->top - mbp->buffer); +} +static inline size_t chMBGetUsedCountI(const mailbox_t *mbp) { + chDbgCheckClassI(); + return mbp->cnt; +} +static inline size_t chMBGetFreeCountI(const mailbox_t *mbp) { + chDbgCheckClassI(); + return chMBGetSizeI(mbp) - chMBGetUsedCountI(mbp); +} +static inline msg_t chMBPeekI(const mailbox_t *mbp) { + chDbgCheckClassI(); + return *mbp->rdptr; +} +static inline void chMBResumeX(mailbox_t *mbp) { + mbp->reset = false; +} +#define CHMEMCORE_H +typedef void *(*memgetfunc_t)(size_t size, unsigned align); +typedef void *(*memgetfunc2_t)(size_t size, unsigned align, size_t offset); +typedef struct { + uint8_t *basemem; + uint8_t *topmem; +} memcore_t; +#define chCoreAllocAlignedWithOffsetI chCoreAllocFromTopI +#define chCoreAllocAlignedWithOffset chCoreAllocFromTop +extern memcore_t ch_memcore; + void _core_init(void); + void *chCoreAllocFromBaseI(size_t size, unsigned align, size_t offset); + void *chCoreAllocFromTopI(size_t size, unsigned align, size_t offset); + void *chCoreAllocFromBase(size_t size, unsigned align, size_t offset); + void *chCoreAllocFromTop(size_t size, unsigned align, size_t offset); + size_t chCoreGetStatusX(void); +static inline void *chCoreAllocAlignedI(size_t size, unsigned align) { + return chCoreAllocAlignedWithOffsetI(size, align, 0U); +} +static inline void *chCoreAllocAligned(size_t size, unsigned align) { + return chCoreAllocAlignedWithOffset(size, align, 0U); +} +static inline void *chCoreAllocI(size_t size) { + return chCoreAllocAlignedWithOffsetI(size, PORT_NATURAL_ALIGN, 0U); +} +static inline void *chCoreAlloc(size_t size) { + return chCoreAllocAlignedWithOffset(size, PORT_NATURAL_ALIGN, 0U); +} +#define CHMEMHEAPS_H +#define CH_HEAP_ALIGNMENT 8U +typedef struct memory_heap memory_heap_t; +typedef union heap_header heap_header_t; +union heap_header { + struct { + heap_header_t *next; + size_t pages; + } free; + struct { + memory_heap_t *heap; + size_t size; + } used; +}; +struct memory_heap { + memgetfunc2_t provider; + heap_header_t header; + mutex_t mtx; +}; +#define CH_HEAP_AREA(name,size) ALIGNED_VAR(CH_HEAP_ALIGNMENT) uint8_t name[MEM_ALIGN_NEXT((size), CH_HEAP_ALIGNMENT)] + void _heap_init(void); + void chHeapObjectInit(memory_heap_t *heapp, void *buf, size_t size); + void *chHeapAllocAligned(memory_heap_t *heapp, size_t size, unsigned align); + void chHeapFree(void *p); + size_t chHeapStatus(memory_heap_t *heapp, size_t *totalp, size_t *largestp); +static inline void *chHeapAlloc(memory_heap_t *heapp, size_t size) { + return chHeapAllocAligned(heapp, size, CH_HEAP_ALIGNMENT); +} +static inline size_t chHeapGetSize(const void *p) { + return ((heap_header_t *)p - 1U)->used.size; +} +#define CHMEMPOOLS_H +struct pool_header { + struct pool_header *next; +}; +typedef struct { + struct pool_header *next; + size_t object_size; + unsigned align; + memgetfunc_t provider; +} memory_pool_t; +typedef struct { + semaphore_t sem; + memory_pool_t pool; +} guarded_memory_pool_t; +#define _MEMORYPOOL_DATA(name,size,align,provider) {NULL, size, align, provider} +#define MEMORYPOOL_DECL(name,size,align,provider) memory_pool_t name = _MEMORYPOOL_DATA(name, size, align, provider) +#define _GUARDEDMEMORYPOOL_DATA(name,size,align) { _SEMAPHORE_DATA(name.sem, (cnt_t)0), _MEMORYPOOL_DATA(NULL, size, align, NULL) } +#define GUARDEDMEMORYPOOL_DECL(name,size,align) guarded_memory_pool_t name = _GUARDEDMEMORYPOOL_DATA(name, size, align) + void chPoolObjectInitAligned(memory_pool_t *mp, size_t size, + unsigned align, memgetfunc_t provider); + void chPoolLoadArray(memory_pool_t *mp, void *p, size_t n); + void *chPoolAllocI(memory_pool_t *mp); + void *chPoolAlloc(memory_pool_t *mp); + void chPoolFreeI(memory_pool_t *mp, void *objp); + void chPoolFree(memory_pool_t *mp, void *objp); + void chGuardedPoolObjectInitAligned(guarded_memory_pool_t *gmp, + size_t size, + unsigned align); + void chGuardedPoolLoadArray(guarded_memory_pool_t *gmp, void *p, size_t n); + void *chGuardedPoolAllocTimeoutS(guarded_memory_pool_t *gmp, + sysinterval_t timeout); + void *chGuardedPoolAllocTimeout(guarded_memory_pool_t *gmp, + sysinterval_t timeout); + void chGuardedPoolFree(guarded_memory_pool_t *gmp, void *objp); +static inline void chPoolObjectInit(memory_pool_t *mp, + size_t size, + memgetfunc_t provider) { + chPoolObjectInitAligned(mp, size, PORT_NATURAL_ALIGN, provider); +} +static inline void chPoolAdd(memory_pool_t *mp, void *objp) { + chPoolFree(mp, objp); +} +static inline void chPoolAddI(memory_pool_t *mp, void *objp) { + chPoolFreeI(mp, objp); +} +static inline void chGuardedPoolObjectInit(guarded_memory_pool_t *gmp, + size_t size) { + chGuardedPoolObjectInitAligned(gmp, size, PORT_NATURAL_ALIGN); +} +static inline cnt_t chGuardedPoolGetCounterI(guarded_memory_pool_t *gmp) { + return chSemGetCounterI(&gmp->sem); +} +static inline void *chGuardedPoolAllocI(guarded_memory_pool_t *gmp) { + void *p; + p = chPoolAllocI(&gmp->pool); + if (p != NULL) { + chSemFastWaitI(&gmp->sem); + chDbgAssert(chSemGetCounterI(&gmp->sem) >= (cnt_t)0, + "semaphore out of sync"); + } + return p; +} +static inline void chGuardedPoolFreeI(guarded_memory_pool_t *gmp, void *objp) { + chPoolFreeI(&gmp->pool, objp); + chSemSignalI(&gmp->sem); +} +static inline void chGuardedPoolFreeS(guarded_memory_pool_t *gmp, void *objp) { + chGuardedPoolFreeI(gmp, objp); + chSchRescheduleS(); +} +static inline void chGuardedPoolAdd(guarded_memory_pool_t *gmp, void *objp) { + chGuardedPoolFree(gmp, objp); +} +static inline void chGuardedPoolAddI(guarded_memory_pool_t *gmp, void *objp) { + chGuardedPoolFreeI(gmp, objp); +} +static inline void chGuardedPoolAddS(guarded_memory_pool_t *gmp, void *objp) { + chGuardedPoolFreeS(gmp, objp); +} +#define CHOBJFIFOS_H +typedef struct ch_objects_fifo { + guarded_memory_pool_t free; + mailbox_t mbx; +} objects_fifo_t; +static inline void chFifoObjectInitAligned(objects_fifo_t *ofp, size_t objsize, + size_t objn, unsigned objalign, + void *objbuf, msg_t *msgbuf) { + chDbgCheck((objsize >= objalign) && ((objsize % objalign) == 0U)); + chGuardedPoolObjectInitAligned(&ofp->free, objsize, objalign); + chGuardedPoolLoadArray(&ofp->free, objbuf, objn); + chMBObjectInit(&ofp->mbx, msgbuf, objn); +} +static inline void chFifoObjectInit(objects_fifo_t *ofp, size_t objsize, + size_t objn, void *objbuf, + msg_t *msgbuf) { + chFifoObjectInitAligned(ofp, objsize, objn, + PORT_NATURAL_ALIGN, + objbuf, msgbuf); +} +static inline void *chFifoTakeObjectI(objects_fifo_t *ofp) { + return chGuardedPoolAllocI(&ofp->free); +} +static inline void *chFifoTakeObjectTimeoutS(objects_fifo_t *ofp, + sysinterval_t timeout) { + return chGuardedPoolAllocTimeoutS(&ofp->free, timeout); +} +static inline void *chFifoTakeObjectTimeout(objects_fifo_t *ofp, + sysinterval_t timeout) { + return chGuardedPoolAllocTimeout(&ofp->free, timeout); +} +static inline void chFifoReturnObjectI(objects_fifo_t *ofp, + void *objp) { + chGuardedPoolFreeI(&ofp->free, objp); +} +static inline void chFifoReturnObjectS(objects_fifo_t *ofp, + void *objp) { + chGuardedPoolFreeS(&ofp->free, objp); +} +static inline void chFifoReturnObject(objects_fifo_t *ofp, + void *objp) { + chGuardedPoolFree(&ofp->free, objp); +} +static inline void chFifoSendObjectI(objects_fifo_t *ofp, + void *objp) { + msg_t msg; + msg = chMBPostI(&ofp->mbx, (msg_t)objp); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline void chFifoSendObjectS(objects_fifo_t *ofp, + void *objp) { + msg_t msg; + msg = chMBPostTimeoutS(&ofp->mbx, (msg_t)objp, TIME_IMMEDIATE); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline void chFifoSendObject(objects_fifo_t *ofp, void *objp) { + msg_t msg; + msg = chMBPostTimeout(&ofp->mbx, (msg_t)objp, TIME_IMMEDIATE); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline void chFifoSendObjectAheadI(objects_fifo_t *ofp, + void *objp) { + msg_t msg; + msg = chMBPostAheadI(&ofp->mbx, (msg_t)objp); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline void chFifoSendObjectAheadS(objects_fifo_t *ofp, + void *objp) { + msg_t msg; + msg = chMBPostAheadTimeoutS(&ofp->mbx, (msg_t)objp, TIME_IMMEDIATE); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline void chFifoSendObjectAhead(objects_fifo_t *ofp, void *objp) { + msg_t msg; + msg = chMBPostAheadTimeout(&ofp->mbx, (msg_t)objp, TIME_IMMEDIATE); + chDbgAssert(msg == MSG_OK, "post failed"); +} +static inline msg_t chFifoReceiveObjectI(objects_fifo_t *ofp, + void **objpp) { + return chMBFetchI(&ofp->mbx, (msg_t *)objpp); +} +static inline msg_t chFifoReceiveObjectTimeoutS(objects_fifo_t *ofp, + void **objpp, + sysinterval_t timeout) { + return chMBFetchTimeoutS(&ofp->mbx, (msg_t *)objpp, timeout); +} +static inline msg_t chFifoReceiveObjectTimeout(objects_fifo_t *ofp, + void **objpp, + sysinterval_t timeout) { + return chMBFetchTimeout(&ofp->mbx, (msg_t *)objpp, timeout); +} +#define CHPIPES_H +typedef struct { + uint8_t *buffer; + uint8_t *top; + uint8_t *wrptr; + uint8_t *rdptr; + size_t cnt; + bool reset; + thread_reference_t wtr; + thread_reference_t rtr; + mutex_t cmtx; + mutex_t wmtx; + mutex_t rmtx; +} pipe_t; +#define _PIPE_DATA(name,buffer,size) { (uint8_t *)(buffer), (uint8_t *)(buffer) + size, (uint8_t *)(buffer), (uint8_t *)(buffer), (size_t)0, false, NULL, NULL, _MUTEX_DATA(name.cmtx), _MUTEX_DATA(name.wmtx), _MUTEX_DATA(name.rmtx), } +#define PIPE_DECL(name,buffer,size) pipe_t name = _PIPE_DATA(name, buffer, size) + void chPipeObjectInit(pipe_t *pp, uint8_t *buf, size_t n); + void chPipeReset(pipe_t *pp); + size_t chPipeWriteTimeout(pipe_t *pp, const uint8_t *bp, + size_t n, sysinterval_t timeout); + size_t chPipeReadTimeout(pipe_t *pp, uint8_t *bp, + size_t n, sysinterval_t timeout); +static inline size_t chPipeGetSize(const pipe_t *pp) { + return (size_t)(pp->top - pp->buffer); +} +static inline size_t chPipeGetUsedCount(const pipe_t *pp) { + return pp->cnt; +} +static inline size_t chPipeGetFreeCount(const pipe_t *pp) { + return chPipeGetSize(pp) - chPipeGetUsedCount(pp); +} +static inline void chPipeResume(pipe_t *pp) { + pp->reset = false; +} +#define CHFACTORY_H +#define CH_FACTORY_REQUIRES_POOLS ((CH_CFG_FACTORY_OBJECTS_REGISTRY == TRUE) || (CH_CFG_FACTORY_SEMAPHORES == TRUE)) +#define CH_FACTORY_REQUIRES_HEAP ((CH_CFG_FACTORY_GENERIC_BUFFERS == TRUE) || (CH_CFG_FACTORY_MAILBOXES == TRUE) || (CH_CFG_FACTORY_OBJ_FIFOS == TRUE) || (CH_CFG_FACTORY_PIPES == TRUE)) +typedef struct ch_dyn_element { + struct ch_dyn_element *next; + ucnt_t refs; + char name[CH_CFG_FACTORY_MAX_NAMES_LENGTH]; +} dyn_element_t; +typedef struct ch_dyn_list { + dyn_element_t *next; +} dyn_list_t; +typedef struct ch_registered_static_object { + dyn_element_t element; + void *objp; +} registered_object_t; +typedef struct ch_dyn_object { + dyn_element_t element; + uint8_t buffer[]; +} dyn_buffer_t; +typedef struct ch_dyn_semaphore { + dyn_element_t element; + semaphore_t sem; +} dyn_semaphore_t; +typedef struct ch_dyn_mailbox { + dyn_element_t element; + mailbox_t mbx; + msg_t msgbuf[]; +} dyn_mailbox_t; +typedef struct ch_dyn_objects_fifo { + dyn_element_t element; + objects_fifo_t fifo; + msg_t msgbuf[]; +} dyn_objects_fifo_t; +typedef struct ch_dyn_pipe { + dyn_element_t element; + pipe_t pipe; + uint8_t buffer[]; +} dyn_pipe_t; +typedef struct ch_objects_factory { + mutex_t mtx; + dyn_list_t obj_list; + memory_pool_t obj_pool; + dyn_list_t buf_list; + dyn_list_t sem_list; + memory_pool_t sem_pool; + dyn_list_t mbx_list; + dyn_list_t fifo_list; + dyn_list_t pipe_list; +} objects_factory_t; +extern objects_factory_t ch_factory; + void _factory_init(void); + registered_object_t *chFactoryRegisterObject(const char *name, + void *objp); + registered_object_t *chFactoryFindObject(const char *name); + registered_object_t *chFactoryFindObjectByPointer(void *objp); + void chFactoryReleaseObject(registered_object_t *rop); + dyn_buffer_t *chFactoryCreateBuffer(const char *name, size_t size); + dyn_buffer_t *chFactoryFindBuffer(const char *name); + void chFactoryReleaseBuffer(dyn_buffer_t *dbp); + dyn_semaphore_t *chFactoryCreateSemaphore(const char *name, cnt_t n); + dyn_semaphore_t *chFactoryFindSemaphore(const char *name); + void chFactoryReleaseSemaphore(dyn_semaphore_t *dsp); + dyn_mailbox_t *chFactoryCreateMailbox(const char *name, size_t n); + dyn_mailbox_t *chFactoryFindMailbox(const char *name); + void chFactoryReleaseMailbox(dyn_mailbox_t *dmp); + dyn_objects_fifo_t *chFactoryCreateObjectsFIFO(const char *name, + size_t objsize, + size_t objn, + unsigned objalign); + dyn_objects_fifo_t *chFactoryFindObjectsFIFO(const char *name); + void chFactoryReleaseObjectsFIFO(dyn_objects_fifo_t *dofp); + dyn_pipe_t *chFactoryCreatePipe(const char *name, size_t size); + dyn_pipe_t *chFactoryFindPipe(const char *name); + void chFactoryReleasePipe(dyn_pipe_t *dpp); +static inline dyn_element_t *chFactoryDuplicateReference(dyn_element_t *dep) { + dep->refs++; + return dep; +} +static inline void *chFactoryGetObject(registered_object_t *rop) { + return rop->objp; +} +static inline size_t chFactoryGetBufferSize(dyn_buffer_t *dbp) { + return chHeapGetSize(dbp) - sizeof (dyn_element_t); +} +static inline uint8_t *chFactoryGetBuffer(dyn_buffer_t *dbp) { + return dbp->buffer; +} +static inline semaphore_t *chFactoryGetSemaphore(dyn_semaphore_t *dsp) { + return &dsp->sem; +} +static inline mailbox_t *chFactoryGetMailbox(dyn_mailbox_t *dmp) { + return &dmp->mbx; +} +static inline objects_fifo_t *chFactoryGetObjectsFIFO(dyn_objects_fifo_t *dofp) { + return &dofp->fifo; +} +static inline pipe_t *chFactoryGetPipe(dyn_pipe_t *dpp) { + return &dpp->pipe; +} +#define CHDYNAMIC_H + thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size, + const char *name, tprio_t prio, + tfunc_t pf, void *arg); + thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, const char *name, + tprio_t prio, tfunc_t pf, void *arg); diff --git a/demos/various/RT-ARMCM4-USELIB/rt/libch.a b/demos/various/RT-ARMCM4-USELIB/rt/libch.a new file mode 100644 index 0000000000000000000000000000000000000000..2510d779473acd2d7c08eea366312588ac332125 GIT binary patch literal 72806 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