From 4ece7f9e71394fd367959a2e5c9513f381788587 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Fri, 25 Sep 2020 12:29:06 +0200 Subject: [PATCH] Adding uC-OS3 --- rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu.h | 655 +++ rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_a.s | 148 + rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_c.c | 695 +++ rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu.h | 762 ++++ rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_a.s | 295 ++ rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_c.c | 772 ++++ rtos/uC-CPU/Cfg/cpu_cfg.h | 254 ++ rtos/uC-CPU/LICENSE | 202 + rtos/uC-CPU/NOTICE | 28 + rtos/uC-CPU/Posix/cpu.h | 535 +++ rtos/uC-CPU/Posix/cpu_c.c | 885 ++++ rtos/uC-CPU/cpu_cache.h | 135 + rtos/uC-CPU/cpu_core.c | 2254 +++++++++ rtos/uC-CPU/cpu_core.h | 1031 +++++ rtos/uC-CPU/cpu_def.h | 212 + rtos/uC-CPU/readme.md | 5 + rtos/uC-LIB/Cfg/lib_cfg.h | 163 + rtos/uC-LIB/LICENSE | 202 + rtos/uC-LIB/NOTICE | 28 + rtos/uC-LIB/Ports/ARM-Cortex-M3/lib_mem_a.s | 298 ++ rtos/uC-LIB/Ports/ARM-Cortex-M4/lib_mem_a.s | 298 ++ rtos/uC-LIB/lib_ascii.c | 644 +++ rtos/uC-LIB/lib_ascii.h | 833 ++++ rtos/uC-LIB/lib_def.h | 1360 ++++++ rtos/uC-LIB/lib_math.c | 270 ++ rtos/uC-LIB/lib_math.h | 287 ++ rtos/uC-LIB/lib_mem.c | 2844 ++++++++++++ rtos/uC-LIB/lib_mem.h | 1438 ++++++ rtos/uC-LIB/lib_str.c | 4031 +++++++++++++++++ rtos/uC-LIB/lib_str.h | 418 ++ rtos/uC-LIB/readme.md | 5 + rtos/uC-OS3/Cfg/app_cfg.h | 105 + rtos/uC-OS3/Cfg/os_app_hooks.c | 262 ++ rtos/uC-OS3/Cfg/os_app_hooks.h | 74 + rtos/uC-OS3/Cfg/os_cfg.h | 118 + rtos/uC-OS3/Cfg/os_cfg_app.h | 80 + rtos/uC-OS3/LICENSE | 202 + rtos/uC-OS3/NOTICE | 28 + .../Ports/ARM-Cortex-M/ARMv6-M/os_cpu.h | 177 + .../Ports/ARM-Cortex-M/ARMv6-M/os_cpu_a.s | 235 + .../Ports/ARM-Cortex-M/ARMv6-M/os_cpu_c.c | 511 +++ .../Ports/ARM-Cortex-M/ARMv7-M/os_cpu.h | 183 + .../Ports/ARM-Cortex-M/ARMv7-M/os_cpu_a.S | 308 ++ .../Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c | 725 +++ rtos/uC-OS3/Ports/POSIX/os_cpu.h | 94 + rtos/uC-OS3/Ports/POSIX/os_cpu_c.c | 730 +++ rtos/uC-OS3/Source/__dbg_uCOS-III.c | 32 + rtos/uC-OS3/Source/os.h | 2436 ++++++++++ rtos/uC-OS3/Source/os_cfg_app.c | 253 ++ rtos/uC-OS3/Source/os_core.c | 2163 +++++++++ rtos/uC-OS3/Source/os_dbg.c | 520 +++ rtos/uC-OS3/Source/os_flag.c | 1298 ++++++ rtos/uC-OS3/Source/os_mem.c | 391 ++ rtos/uC-OS3/Source/os_msg.c | 349 ++ rtos/uC-OS3/Source/os_mutex.c | 1129 +++++ rtos/uC-OS3/Source/os_prio.c | 183 + rtos/uC-OS3/Source/os_q.c | 987 ++++ rtos/uC-OS3/Source/os_sem.c | 966 ++++ rtos/uC-OS3/Source/os_stat.c | 571 +++ rtos/uC-OS3/Source/os_task.c | 2843 ++++++++++++ rtos/uC-OS3/Source/os_tick.c | 577 +++ rtos/uC-OS3/Source/os_time.c | 600 +++ rtos/uC-OS3/Source/os_tmr.c | 1657 +++++++ rtos/uC-OS3/Source/os_trace.h | 476 ++ rtos/uC-OS3/Source/os_type.h | 87 + rtos/uC-OS3/Source/os_var.c | 33 + rtos/uC-OS3/readme.md | 7 + 67 files changed, 43377 insertions(+) create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu.h create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_a.s create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_c.c create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu.h create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_a.s create mode 100644 rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_c.c create mode 100644 rtos/uC-CPU/Cfg/cpu_cfg.h create mode 100644 rtos/uC-CPU/LICENSE create mode 100644 rtos/uC-CPU/NOTICE create mode 100644 rtos/uC-CPU/Posix/cpu.h create mode 100644 rtos/uC-CPU/Posix/cpu_c.c create mode 100644 rtos/uC-CPU/cpu_cache.h create mode 100644 rtos/uC-CPU/cpu_core.c create mode 100644 rtos/uC-CPU/cpu_core.h create mode 100644 rtos/uC-CPU/cpu_def.h create mode 100644 rtos/uC-CPU/readme.md create mode 100644 rtos/uC-LIB/Cfg/lib_cfg.h create mode 100644 rtos/uC-LIB/LICENSE create mode 100644 rtos/uC-LIB/NOTICE create mode 100644 rtos/uC-LIB/Ports/ARM-Cortex-M3/lib_mem_a.s create mode 100644 rtos/uC-LIB/Ports/ARM-Cortex-M4/lib_mem_a.s create mode 100644 rtos/uC-LIB/lib_ascii.c create mode 100644 rtos/uC-LIB/lib_ascii.h create mode 100644 rtos/uC-LIB/lib_def.h create mode 100644 rtos/uC-LIB/lib_math.c create mode 100644 rtos/uC-LIB/lib_math.h create mode 100644 rtos/uC-LIB/lib_mem.c create mode 100644 rtos/uC-LIB/lib_mem.h create mode 100644 rtos/uC-LIB/lib_str.c create mode 100644 rtos/uC-LIB/lib_str.h create mode 100644 rtos/uC-LIB/readme.md create mode 100644 rtos/uC-OS3/Cfg/app_cfg.h create mode 100644 rtos/uC-OS3/Cfg/os_app_hooks.c create mode 100644 rtos/uC-OS3/Cfg/os_app_hooks.h create mode 100644 rtos/uC-OS3/Cfg/os_cfg.h create mode 100644 rtos/uC-OS3/Cfg/os_cfg_app.h create mode 100644 rtos/uC-OS3/LICENSE create mode 100644 rtos/uC-OS3/NOTICE create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu.h create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_a.s create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_c.c create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu.h create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_a.S create mode 100644 rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c create mode 100644 rtos/uC-OS3/Ports/POSIX/os_cpu.h create mode 100644 rtos/uC-OS3/Ports/POSIX/os_cpu_c.c create mode 100644 rtos/uC-OS3/Source/__dbg_uCOS-III.c create mode 100644 rtos/uC-OS3/Source/os.h create mode 100644 rtos/uC-OS3/Source/os_cfg_app.c create mode 100644 rtos/uC-OS3/Source/os_core.c create mode 100644 rtos/uC-OS3/Source/os_dbg.c create mode 100644 rtos/uC-OS3/Source/os_flag.c create mode 100644 rtos/uC-OS3/Source/os_mem.c create mode 100644 rtos/uC-OS3/Source/os_msg.c create mode 100644 rtos/uC-OS3/Source/os_mutex.c create mode 100644 rtos/uC-OS3/Source/os_prio.c create mode 100644 rtos/uC-OS3/Source/os_q.c create mode 100644 rtos/uC-OS3/Source/os_sem.c create mode 100644 rtos/uC-OS3/Source/os_stat.c create mode 100644 rtos/uC-OS3/Source/os_task.c create mode 100644 rtos/uC-OS3/Source/os_tick.c create mode 100644 rtos/uC-OS3/Source/os_time.c create mode 100644 rtos/uC-OS3/Source/os_tmr.c create mode 100644 rtos/uC-OS3/Source/os_trace.h create mode 100644 rtos/uC-OS3/Source/os_type.h create mode 100644 rtos/uC-OS3/Source/os_var.c create mode 100644 rtos/uC-OS3/readme.md diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu.h b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu.h new file mode 100644 index 00000000..c7d0798c --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu.h @@ -0,0 +1,655 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARMv6-M +* GNU C Compiler +* +* Filename : cpu.h +* Version : v1.32.00 +********************************************************************************************************* +* Note(s) : This port supports the ARM Cortex-M0, and Cortex-M0+ architectures. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU header file is protected from multiple pre-processor inclusion through use of +* the CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_MODULE_PRESENT /* See Note #1. */ +#define CPU_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU INCLUDE FILES +* +* Note(s) : (1) The following CPU files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_def.h +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (2) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (3) Since NO custom library modules are included, 'cpu.h' may ONLY use configurations from +* CPU configuration file 'cpu_cfg.h' that do NOT reference any custom library definitions. +* +* In other words, 'cpu.h' may use 'cpu_cfg.h' configurations that are #define'd to numeric +* constants or to NULL (i.e. NULL-valued #define's); but may NOT use configurations to +* custom library #define's (e.g. DEF_DISABLED or DEF_ENABLED). +********************************************************************************************************* +*/ + +#include +#include /* See Note #3. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* CONFIGURE STANDARD DATA TYPES +* +* Note(s) : (1) Configure standard data types according to CPU-/compiler-specifications. +* +* (2) (a) (1) 'CPU_FNCT_VOID' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has no arguments. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_VOID FnctName; +* +* FnctName(); +* +* (b) (1) 'CPU_FNCT_PTR' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has a single void +* pointer argument. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_PTR FnctName; +* void *p_obj +* +* FnctName(p_obj); +********************************************************************************************************* +*/ + +typedef void CPU_VOID; +typedef char CPU_CHAR; /* 8-bit character */ +typedef unsigned char CPU_BOOLEAN; /* 8-bit boolean or logical */ +typedef unsigned char CPU_INT08U; /* 8-bit unsigned integer */ +typedef signed char CPU_INT08S; /* 8-bit signed integer */ +typedef unsigned short CPU_INT16U; /* 16-bit unsigned integer */ +typedef signed short CPU_INT16S; /* 16-bit signed integer */ +typedef unsigned int CPU_INT32U; /* 32-bit unsigned integer */ +typedef signed int CPU_INT32S; /* 32-bit signed integer */ +typedef unsigned long long CPU_INT64U; /* 64-bit unsigned integer */ +typedef signed long long CPU_INT64S; /* 64-bit signed integer */ + +typedef float CPU_FP32; /* 32-bit floating point */ +typedef double CPU_FP64; /* 64-bit floating point */ + + +typedef volatile CPU_INT08U CPU_REG08; /* 8-bit register */ +typedef volatile CPU_INT16U CPU_REG16; /* 16-bit register */ +typedef volatile CPU_INT32U CPU_REG32; /* 32-bit register */ +typedef volatile CPU_INT64U CPU_REG64; /* 64-bit register */ + + +typedef void (*CPU_FNCT_VOID)(void); /* See Note #2a. */ +typedef void (*CPU_FNCT_PTR )(void *p_obj); /* See Note #2b. */ + + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE, CPU_CFG_DATA_SIZE, & CPU_CFG_DATA_SIZE_MAX with CPU's &/or +* compiler's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* Define CPU word sizes (see Note #1) : */ +#define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_32 /* Defines CPU address word size (in octets). */ +#define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_32 /* Defines CPU data word size (in octets). */ +#define CPU_CFG_DATA_SIZE_MAX CPU_WORD_SIZE_64 /* Defines CPU maximum word size (in octets). */ + +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_LITTLE /* Defines CPU data word-memory order (see Note #2). */ + + +/* +********************************************************************************************************* +* CONFIGURE CPU ADDRESS & DATA TYPES +********************************************************************************************************* +*/ + + /* CPU address type based on address bus size. */ +#if (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_ADDR; +#elif (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_ADDR; +#else +typedef CPU_INT08U CPU_ADDR; +#endif + + /* CPU data type based on data bus size. */ +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_DATA; +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_DATA; +#else +typedef CPU_INT08U CPU_DATA; +#endif + + +typedef CPU_DATA CPU_ALIGN; /* Defines CPU data-word-alignment size. */ +typedef CPU_ADDR CPU_SIZE_T; /* Defines CPU standard 'size_t' size. */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +* +* (2) Configure CPU_CFG_STK_ALIGN_BYTES with the highest minimum alignement required for +* cpu stacks. +* +* (a) ARM Procedure Calls Standard requires an 8 bytes stack alignment. +********************************************************************************************************* +*/ + +#define CPU_CFG_STK_GROWTH CPU_STK_GROWTH_HI_TO_LO /* Defines CPU stack growth order (see Note #1). */ + +#define CPU_CFG_STK_ALIGN_BYTES (8u) /* Defines CPU stack alignment in bytes. (see Note #2). */ + +typedef CPU_INT32U CPU_STK; /* Defines CPU stack data type. */ +typedef CPU_ADDR CPU_STK_SIZE; /* Defines CPU stack size data type. */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable should be declared via the CPU_SR_ALLOC() macro which, if +* used, MUST be declared following ALL other local variables. +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + /* Configure CPU critical method (see Note #1) : */ +#define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_STATUS_LOCAL + +typedef CPU_INT32U CPU_SR; /* Defines CPU status register size (see Note #3b). */ + + /* Allocates CPU status register word (see Note #3a). */ +#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) +#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 +#else +#define CPU_SR_ALLOC() +#endif + +#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0) /* Save CPU status word & disable interrupts.*/ +#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0) /* Restore CPU status word. */ + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + /* Disable interrupts, ... */ + /* & start interrupts disabled time measurement.*/ +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \ + CPU_IntDisMeasStart(); } while (0) + /* Stop & measure interrupts disabled time, */ + /* ... & re-enable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \ + CPU_INT_EN(); } while (0) + +#else + +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) /* Disable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0) /* Re-enable interrupts. */ + +#endif + + +/* +********************************************************************************************************* +* MEMORY BARRIERS CONFIGURATION +* +* Note(s) : (1) (a) Configure memory barriers if required by the architecture. +* +* CPU_MB Full memory barrier. +* CPU_RMB Read (Loads) memory barrier. +* CPU_WMB Write (Stores) memory barrier. +* +********************************************************************************************************* +*/ + +#define CPU_MB() __asm__ __volatile__ ("dsb" : : : "memory") +#define CPU_RMB() __asm__ __volatile__ ("dsb" : : : "memory") +#define CPU_WMB() __asm__ __volatile__ ("dsb" : : : "memory") + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void CPU_IntDis (void); +void CPU_IntEn (void); + +void CPU_IntSrcDis (CPU_INT08U pos); +void CPU_IntSrcEn (CPU_INT08U pos); +void CPU_IntSrcPendClr(CPU_INT08U pos); +CPU_INT16S CPU_IntSrcPrioGet(CPU_INT08U pos); +void CPU_IntSrcPrioSet(CPU_INT08U pos, + CPU_INT08U prio); + + +CPU_SR CPU_SR_Save (void); +void CPU_SR_Restore (CPU_SR cpu_sr); + + +void CPU_WaitForInt (void); +void CPU_WaitForExcept(void); + + +CPU_DATA CPU_RevBits (CPU_DATA val); /* C-code replacement for asm function */ + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr); +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr); + + +/* +********************************************************************************************************* +* INTERRUPT SOURCES +********************************************************************************************************* +*/ + +#define CPU_INT_STK_PTR 0u +#define CPU_INT_RESET 1u +#define CPU_INT_NMI 2u +#define CPU_INT_HFAULT 3u +#define CPU_INT_RSVD_04 4u /* RSVD interrupts may be designated on newer models */ +#define CPU_INT_RSVD_05 5u +#define CPU_INT_RSVD_06 6u +#define CPU_INT_RSVD_07 7u +#define CPU_INT_RSVD_08 8u +#define CPU_INT_RSVD_09 9u +#define CPU_INT_RSVD_10 10u +#define CPU_INT_SVCALL 11u +#define CPU_INT_RSVD_12 12u +#define CPU_INT_RSVD_13 13u +#define CPU_INT_PENDSV 14u +#define CPU_INT_SYSTICK 15u +#define CPU_INT_EXT0 16u + + +/* +********************************************************************************************************* +* CPU REGISTERS +********************************************************************************************************* +*/ + /* -------- SYSTICK REGISTERS --------- */ +#define CPU_REG_SYST_CSR (*((CPU_REG32 *)(0xE000E010))) /* SysTick Ctrl & Status Reg. */ +#define CPU_REG_SYST_RVR (*((CPU_REG32 *)(0xE000E014))) /* SysTick Reload Value Reg. */ +#define CPU_REG_SYST_CVR (*((CPU_REG32 *)(0xE000E018))) /* SysTick Current Value Reg. */ +#define CPU_REG_SYST_CALIB (*((CPU_REG32 *)(0xE000E01C))) /* SysTick Calibration Value Reg. */ + + /* ---------- NVIC REGISTERS ---------- */ +#define CPU_REG_NVIC_ISER(n) (*((CPU_REG32 *)(0xE000E100 + (n) * 4u))) /* IRQ Set En Reg. */ +#define CPU_REG_NVIC_ICER(n) (*((CPU_REG32 *)(0xE000E180 + (n) * 4u))) /* IRQ Clr En Reg. */ +#define CPU_REG_NVIC_ISPR(n) (*((CPU_REG32 *)(0xE000E200 + (n) * 4u))) /* IRQ Set Pending Reg. */ +#define CPU_REG_NVIC_ICPR(n) (*((CPU_REG32 *)(0xE000E280 + (n) * 4u))) /* IRQ Clr Pending Reg. */ +#define CPU_REG_NVIC_IPR(n) (*((CPU_REG32 *)(0xE000E400 + (n) * 4u))) /* IRQ Prio Reg. */ + + /* -- SYSTEM CONTROL BLOCK(SCB) REG -- */ +#define CPU_REG_SCB_CPUID (*((CPU_REG32 *)(0xE000ED00))) /* CPUID Base Reg. */ +#define CPU_REG_SCB_ICSR (*((CPU_REG32 *)(0xE000ED04))) /* Int Ctrl State Reg. */ +#define CPU_REG_SCB_VTOR (*((CPU_REG32 *)(0xE000ED08))) /* Vect Tbl Offset Reg. */ +#define CPU_REG_SCB_AIRCR (*((CPU_REG32 *)(0xE000ED0C))) /* App Int/Reset Ctrl Reg. */ +#define CPU_REG_SCB_SCR (*((CPU_REG32 *)(0xE000ED10))) /* System Ctrl Reg. */ +#define CPU_REG_SCB_CCR (*((CPU_REG32 *)(0xE000ED14))) /* Cfg Ctrl Reg. */ +#define CPU_REG_SCB_SHPRI2 (*((CPU_REG32 *)(0xE000ED1C))) /* System Handlers 8 to 11 Prio. */ +#define CPU_REG_SCB_SHPRI3 (*((CPU_REG32 *)(0xE000ED20))) /* System Handlers 12 to 15 Prio. */ +#define CPU_REG_SCB_SHCSR (*((CPU_REG32 *)(0xE000ED24))) /* System Handler Ctrl & State Reg. */ +#define CPU_REG_SCB_DFSR (*((CPU_REG32 *)(0xE000ED30))) /* Debug Fault Status Reg. */ + + /* ---------- CPUID REGISTERS --------- */ +#define CPU_REG_CPUID_MMFR0 (*((CPU_REG32 *)(0xE000ED50))) /* Memory Model Feature Reg 0. */ +#define CPU_REG_CPUID_MMFR1 (*((CPU_REG32 *)(0xE000ED54))) /* Memory Model Feature Reg 1. */ +#define CPU_REG_CPUID_MMFR2 (*((CPU_REG32 *)(0xE000ED58))) /* Memory Model Feature Reg 2. */ +#define CPU_REG_CPUID_MMFR3 (*((CPU_REG32 *)(0xE000ED5C))) /* Memory Model Feature Reg 3. */ +#define CPU_REG_CPUID_ISAFR0 (*((CPU_REG32 *)(0xE000ED60))) /* ISA Feature Reg 0. */ +#define CPU_REG_CPUID_ISAFR1 (*((CPU_REG32 *)(0xE000ED64))) /* ISA Feature Reg 1. */ +#define CPU_REG_CPUID_ISAFR2 (*((CPU_REG32 *)(0xE000ED68))) /* ISA Feature Reg 2. */ +#define CPU_REG_CPUID_ISAFR3 (*((CPU_REG32 *)(0xE000ED6C))) /* ISA Feature Reg 3. */ +#define CPU_REG_CPUID_ISAFR4 (*((CPU_REG32 *)(0xE000ED70))) /* ISA Feature Reg 4. */ + + /* ----------- MPU REGISTERS ---------- */ +#define CPU_REG_MPU_TYPE (*((CPU_REG32 *)(0xE000ED90))) /* MPU Type Reg. */ +#define CPU_REG_MPU_CTRL (*((CPU_REG32 *)(0xE000ED94))) /* MPU Ctrl Reg. */ +#define CPU_REG_MPU_RNR (*((CPU_REG32 *)(0xE000ED98))) /* MPU Region Nbr Reg. */ +#define CPU_REG_MPU_RBAR (*((CPU_REG32 *)(0xE000ED9C))) /* MPU Region Base Addr Reg. */ +#define CPU_REG_MPU_RASR (*((CPU_REG32 *)(0xE000EDA0))) /* MPU Region Attrib & Size Reg. */ + + /* ----- REGISTERS NOT IN THE SCB ----- */ +#define CPU_REG_ICTR (*((CPU_REG32 *)(0xE000E004))) /* Int Ctrl'er Type Reg. */ +#define CPU_REG_DCRSR (*((CPU_REG32 *)(0xE000EDF4))) /* Debug Core Reg Selector Reg. */ +#define CPU_REG_DCRDR (*((CPU_REG32 *)(0xE000EDF8))) /* Debug Core Reg Data Reg. */ +#define CPU_REG_DEMCR (*((CPU_REG32 *)(0xE000EDFC))) /* Debug Except & Monitor Ctrl Reg. */ +#define CPU_REG_STIR (*((CPU_REG32 *)(0xE000EF00))) /* Software Trigger Int Reg. */ + + +/* +********************************************************************************************************* +* CPU REGISTER BITS +********************************************************************************************************* +*/ + + /* ---------- SYSTICK CTRL & STATUS REG BITS ---------- */ +#define CPU_REG_SYST_CSR_COUNTFLAG 0x00010000 +#define CPU_REG_SYST_CSR_CLKSOURCE 0x00000004 +#define CPU_REG_SYST_CSR_TICKINT 0x00000002 +#define CPU_REG_SYST_CSR_ENABLE 0x00000001 + + /* -------- SYSTICK CALIBRATION VALUE REG BITS -------- */ +#define CPU_REG_SYST_CALIB_NOREF 0x80000000 +#define CPU_REG_SYST_CALIB_SKEW 0x40000000 + + /* -------------- INT CTRL STATE REG BITS ------------- */ +#define CPU_REG_SCB_ICSR_NMIPENDSET 0x80000000 +#define CPU_REG_SCB_ICSR_PENDSVSET 0x10000000 +#define CPU_REG_SCB_ICSR_PENDSVCLR 0x08000000 +#define CPU_REG_SCB_ICSR_PENDSTSET 0x04000000 +#define CPU_REG_SCB_ICSR_PENDSTCLR 0x02000000 +#define CPU_REG_SCB_ICSR_ISRPREEMPT 0x00800000 +#define CPU_REG_SCB_ICSR_ISRPENDING 0x00400000 + + /* ------------- VECT TBL OFFSET REG BITS ------------- */ +#define CPU_REG_SCB_VTOR_TBLBASE 0x20000000 + + /* ------------ APP INT/RESET CTRL REG BITS ----------- */ +#define CPU_REG_SCB_AIRCR_ENDIANNESS 0x00008000 +#define CPU_REG_SCB_AIRCR_SYSRESETREQ 0x00000004 +#define CPU_REG_SCB_AIRCR_VECTCLRACTIVE 0x00000002 + + /* --------------- SYSTEM CTRL REG BITS --------------- */ +#define CPU_REG_SCB_SCR_SEVONPEND 0x00000010 +#define CPU_REG_SCB_SCR_SLEEPDEEP 0x00000004 +#define CPU_REG_SCB_SCR_SLEEPONEXIT 0x00000002 + + /* ----------------- CFG CTRL REG BITS ---------------- */ +#define CPU_REG_SCB_CCR_STKALIGN 0x00000200 +#define CPU_REG_SCB_CCR_UNALIGN_TRP 0x00000008 + + /* ------- SYSTEM HANDLER CTRL & STATE REG BITS ------- */ +#define CPU_REG_SCB_SHCSR_SVCALLPENDED 0x00008000 + + /* ------------ DEBUG FAULT STATUS REG BITS ----------- */ +#define CPU_REG_SCB_DFSR_EXTERNAL 0x00000010 +#define CPU_REG_SCB_DFSR_VCATCH 0x00000008 +#define CPU_REG_SCB_DFSR_DWTTRAP 0x00000004 +#define CPU_REG_SCB_DFSR_BKPT 0x00000002 +#define CPU_REG_SCB_DFSR_HALTED 0x00000001 + + +/* +********************************************************************************************************* +* CPU REGISTER MASK +********************************************************************************************************* +*/ + +#define CPU_MSK_SCB_ICSR_VECT_ACTIVE 0x000001FF + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_ADDR_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + + +#if (CPU_CFG_DATA_SIZE_MAX < CPU_CFG_DATA_SIZE) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be >= CPU_CFG_DATA_SIZE]" +#endif + + + + +#ifndef CPU_CFG_ENDIAN_TYPE +#error "CPU_CFG_ENDIAN_TYPE not #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" + +#elif ((CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_BIG ) && \ + (CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_LITTLE)) +#error "CPU_CFG_ENDIAN_TYPE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" +#endif + + + + +#ifndef CPU_CFG_STK_GROWTH +#error "CPU_CFG_STK_GROWTH not #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" + +#elif ((CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_LO_TO_HI) && \ + (CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_HI_TO_LO)) +#error "CPU_CFG_STK_GROWTH illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" +#endif + + + + +#ifndef CPU_CFG_CRITICAL_METHOD +#error "CPU_CFG_CRITICAL_METHOD not #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" + +#elif ((CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_INT_DIS_EN ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_STK ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_LOCAL)) +#error "CPU_CFG_CRITICAL_METHOD illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu.h MODULE'. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* End of CPU module include. */ + diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_a.s b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_a.s new file mode 100644 index 00000000..65579fd5 --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_a.s @@ -0,0 +1,148 @@ +@******************************************************************************************************** +@ uC/CPU +@ CPU CONFIGURATION & PORT LAYER +@ +@ Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + +@******************************************************************************************************** +@ +@ CPU PORT FILE +@ +@ ARMv6-M +@ GNU C Compiler +@ +@ Filename : cpu_a.s +@ Version : v1.32.00 +@******************************************************************************************************** +@ Note(s) : This port supports the ARM Cortex-M0, and Cortex-M0+ architectures. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + +.global CPU_IntDis +.global CPU_IntEn + +.global CPU_SR_Save +.global CPU_SR_Restore + +.global CPU_WaitForInt +.global CPU_WaitForExcept + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + +.text +.align 2 +.thumb +.syntax unified + + +@******************************************************************************************************** +@ DISABLE and ENABLE INTERRUPTS +@ +@ Description : Disable/Enable interrupts. +@ +@ Prototypes : void CPU_IntDis(void); +@ void CPU_IntEn (void); +@******************************************************************************************************** + +.thumb_func +CPU_IntDis: + CPSID I + BX LR + +.thumb_func +CPU_IntEn: + CPSIE I + BX LR + + +@******************************************************************************************************** +@ CRITICAL SECTION FUNCTIONS +@ +@ Description : Disable/Enable interrupts by preserving the state of interrupts. Generally speaking, the +@ state of the interrupt disable flag is stored in the local variable 'cpu_sr' & interrupts +@ are then disabled ('cpu_sr' is allocated in all functions that need to disable interrupts). +@ The previous interrupt state is restored by copying 'cpu_sr' into the CPU's status register. +@ +@ Prototypes : CPU_SR CPU_SR_Save (void); +@ void CPU_SR_Restore(CPU_SR cpu_sr); +@ +@ Note(s) : (1) These functions are used in general like this : +@ +@ void Task (void *p_arg) +@ { +@ CPU_SR_ALLOC(); /* Allocate storage for CPU status register */ +@ : +@ : +@ CPU_CRITICAL_ENTER(); /* cpu_sr = CPU_SR_Save(); */ +@ : +@ : +@ CPU_CRITICAL_EXIT(); /* CPU_SR_Restore(cpu_sr); */ +@ : +@ } +@******************************************************************************************************** + +.thumb_func +CPU_SR_Save: + MRS R0, PRIMASK @ Set prio int mask to mask all (except faults) + CPSID I + BX LR + +.thumb_func +CPU_SR_Restore: @ See Note #2. + MSR PRIMASK, R0 + BX LR + + +@******************************************************************************************************** +@ WAIT FOR INTERRUPT +@ +@ Description : Enters sleep state, which will be exited when an interrupt is received. +@ +@ Prototypes : void CPU_WaitForInt (void) +@ +@ Argument(s) : none. +@******************************************************************************************************** + +.thumb_func +CPU_WaitForInt: + WFI @ Wait for interrupt + BX LR + + +@******************************************************************************************************** +@ WAIT FOR EXCEPTION +@ +@ Description : Enters sleep state, which will be exited when an exception is received. +@ +@ Prototypes : void CPU_WaitForExcept (void) +@ +@ Argument(s) : none. +@******************************************************************************************************** + +.thumb_func +CPU_WaitForExcept: + WFE @ Wait for exception + BX LR + + +@******************************************************************************************************** +@ CPU ASSEMBLY PORT FILE END +@******************************************************************************************************** + +.end + diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_c.c b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_c.c new file mode 100644 index 00000000..17b88a2c --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv6-M/cpu_c.c @@ -0,0 +1,695 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARMv6-M +* +* Filename : cpu_c.c +* Version : v1.32.00 +********************************************************************************************************* +* Note(s) : This port supports the ARM Cortex-M0, and Cortex-M0+ architectures. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + +#define CPU_INT_SRC_POS_MAX ((((CPU_REG_ICTR + 1) & 0x1F) * 32) + 16) + +#define CPU_BIT_BAND_SRAM_REG_LO 0x20000000 +#define CPU_BIT_BAND_SRAM_REG_HI 0x200FFFFF +#define CPU_BIT_BAND_SRAM_BASE 0x22000000 + + +#define CPU_BIT_BAND_PERIPH_REG_LO 0x40000000 +#define CPU_BIT_BAND_PERIPH_REG_HI 0x400FFFFF +#define CPU_BIT_BAND_PERIPH_BASE 0x42000000 + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +* +* Note(s) : (1) Determines the interrupt programmable priority levels. This is normally specified in the +* Microcontroller reference manual. 2-bits gives us 4 programmable priority levels. +* +* NVIC_IPRx +* 7 0 +* +------------------+ +* | PRIO | +* +------------------+ +* +* Bits[7:6] Priority mask bits +* Bits[5:0] Reserved +* +* In this example our CPU_CFG_NVIC_PRIO_BITS define should be set to 2 due to the processor +* implementing only bits[7:6]. +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_NVIC_PRIO_BITS +#error "CPU_CFG_NVIC_PRIO_BITS not #define'd in 'cpu_cfg.h' " /* See Note # 1 */ +#endif + + +/* +********************************************************************************************************* +* CPU_BitBandClr() +* +* Description : Clear bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + } +} + + +/* +********************************************************************************************************* +* CPU_BitBandSet() +* +* Description : Set bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcDis() +* +* Description : Disable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table : +* +* 0 Invalid (see Note #1a). +* 1 Invalid (see Note #1b). +* 2 Non-maskable Interrupt. +* 3 Hard Fault. +* 4 Memory Management. +* 5 Bus Fault. +* 6 Usage Fault. +* 7-10 Reserved. +* 11 SVCall. +* 12 Debug Monitor. +* 13 Reserved. +* 14 PendSV. +* 15 SysTick. +* 16+ External Interrupt. +* +* Return(s) : none. +* +* Note(s) : (1) Several table positions do not contain interrupt sources : +* +* (a) Position 0 contains the stack pointer. +* (b) Positions 7-10, 13 are reserved. +* +* (2) Several interrupts cannot be disabled/enabled : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) SVCall. +* (e) Debug monitor. +* (f) PendSV. +* +* (3) The maximum Cortex-M0 table position is 256. A particular Cortex-M0 may have fewer +* than 240 external exceptions and, consequently, fewer than 256 table positions. +* This function assumes that the specified table position is valid if the interrupt +* controller type register's INTLINESNUM field is large enough so that the position +* COULD be valid. +********************************************************************************************************* +*/ + +void CPU_IntSrcDis (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U pos_max; + CPU_INT08U nbr; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SYST_CSR &= ~CPU_REG_SYST_CSR_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ICER(group) = DEF_BIT(nbr); /* Disable interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcEn() +* +* Description : Enable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcDis() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcEn (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ISER(group) = DEF_BIT(nbr); /* Enable interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPendClr() +* +* Description : Clear a pending interrupt. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) The pending status of several interrupts cannot be clear/set : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) Memory Managment. +* (e) Bus Fault. +* (f) Usage Fault. +* (g) SVCall. +* (h) Debug monitor. +* (i) PendSV. +* (j) Systick +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcPendClr (CPU_INT08U pos) + +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + case CPU_INT_SYSTICK: /* SysTick. */ + break; + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ICPR(group) = DEF_BIT(nbr); /* Clear Pending interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioSet() +* +* Description : Set priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* prio Priority. Use a lower priority number for a higher priority. +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) Several interrupts priorities CANNOT be set : +* +* (a) Reset (always -3). +* (b) NMI (always -2). +* (c) Hard fault (always -1). +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcPrioSet (CPU_INT08U pos, + CPU_INT08U prio) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_INT32U temp; + CPU_INT32U prio_offset; + CPU_SR_ALLOC(); + + + prio_offset = (prio << (DEF_OCTET_NBR_BITS - CPU_CFG_NVIC_PRIO_BITS)); + if (prio >= (1u << CPU_CFG_NVIC_PRIO_BITS)) { /* Priority should not exceed the max allowed by MCU */ + CPU_SW_Exception(); + } + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI2; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI2 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (2 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_IPR(group); + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (nbr * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (nbr * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_IPR(group) = temp; /* Set interrupt priority. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioGet() +* +* Description : Get priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : Priority of interrupt source. If the interrupt source specified is invalid, then +* DEF_INT_16S_MIN_VAL is returned. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcPrioSet() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +CPU_INT16S CPU_IntSrcPrioGet (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT08U pos_max; + CPU_INT16S prio; + CPU_INT32U temp; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + prio = DEF_INT_16S_MIN_VAL; + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + prio = -3; + break; + + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + prio = -2; + break; + + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + prio = -1; + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI2; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + prio = (temp >> (2 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_IPR(group); /* Read group interrupt priority. */ + CPU_CRITICAL_EXIT(); + + prio = (temp >> (nbr * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + } else { + prio = DEF_INT_16S_MIN_VAL; + } + break; + } + + if (prio != DEF_INT_16S_MIN_VAL) { + prio = (prio >> (DEF_OCTET_NBR_BITS - CPU_CFG_NVIC_PRIO_BITS)); + } + + return (prio); +} + + +/* +********************************************************************************************************* +* CPU_RevBits() +*Description : Reverses the bits in a data value. +* +* Prototypes : CPU_DATA CPU_RevBits(CPU_DATA val); +* +* Argument(s) : val Data value to reverse bits. +* +* Return(s) : Value with all bits in 'val' reversed (see Note #1). +* +* Note(s) : (1) val is a 32-bit number +* (2) Goes through a number and checks for sets bits which are then set +* in the reverse locations: +* +* reverse_val => 0b00000....00 +* val => 0101100....10 +* val's 2nd bit is set => reverse_val's bit (num_bits - 1 - count) +* val's 5th bit is set => reverse_val's bit (num_bits - 1 - count) +* ... ... +* ... ... +* +********************************************************************************************************* +*/ + +CPU_DATA CPU_RevBits(CPU_DATA val) +{ + CPU_DATA reverse_val; + CPU_INT08U nbr_bits; /* establish how many bits are in val */ + CPU_INT32U cnt; /* for stepping through each bit in val */ + CPU_INT32U tmp; /* gets shifted off bit to check if set or not */ + + + nbr_bits = sizeof(CPU_DATA) * 8; + reverse_val = 0; /* make sure reverse_val is cleared out to zeros */ + + for (cnt = 0; cnt < nbr_bits; cnt++) + { + tmp = (val & (1 << cnt)); /* shift the next bit into tmp */ + + if(tmp) { + reverse_val |= (1 << ((nbr_bits - 1) - cnt)); /* shift in a 1 bit to reverse equivalent bit */ + } + } + + return (reverse_val); +} + +#ifdef __cplusplus +} +#endif diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu.h b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu.h new file mode 100644 index 00000000..060c0db2 --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu.h @@ -0,0 +1,762 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARMv7-M +* GNU C Compiler +* +* Filename : cpu.h +* Version : v1.32.00 +********************************************************************************************************* +* Note(s) : This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU header file is protected from multiple pre-processor inclusion through use of +* the CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_MODULE_PRESENT /* See Note #1. */ +#define CPU_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU INCLUDE FILES +* +* Note(s) : (1) The following CPU files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_def.h +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (2) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (3) Since NO custom library modules are included, 'cpu.h' may ONLY use configurations from +* CPU configuration file 'cpu_cfg.h' that do NOT reference any custom library definitions. +* +* In other words, 'cpu.h' may use 'cpu_cfg.h' configurations that are #define'd to numeric +* constants or to NULL (i.e. NULL-valued #define's); but may NOT use configurations to +* custom library #define's (e.g. DEF_DISABLED or DEF_ENABLED). +********************************************************************************************************* +*/ + +#include +#include /* See Note #3. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* CONFIGURE STANDARD DATA TYPES +* +* Note(s) : (1) Configure standard data types according to CPU-/compiler-specifications. +* +* (2) (a) (1) 'CPU_FNCT_VOID' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has no arguments. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_VOID FnctName; +* +* FnctName(); +* +* (b) (1) 'CPU_FNCT_PTR' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has a single void +* pointer argument. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_PTR FnctName; +* void *p_obj +* +* FnctName(p_obj); +********************************************************************************************************* +*/ + +typedef void CPU_VOID; +typedef char CPU_CHAR; /* 8-bit character */ +typedef unsigned char CPU_BOOLEAN; /* 8-bit boolean or logical */ +typedef unsigned char CPU_INT08U; /* 8-bit unsigned integer */ +typedef signed char CPU_INT08S; /* 8-bit signed integer */ +typedef unsigned short CPU_INT16U; /* 16-bit unsigned integer */ +typedef signed short CPU_INT16S; /* 16-bit signed integer */ +typedef unsigned int CPU_INT32U; /* 32-bit unsigned integer */ +typedef signed int CPU_INT32S; /* 32-bit signed integer */ +typedef unsigned long long CPU_INT64U; /* 64-bit unsigned integer */ +typedef signed long long CPU_INT64S; /* 64-bit signed integer */ + +typedef float CPU_FP32; /* 32-bit floating point */ +typedef double CPU_FP64; /* 64-bit floating point */ + + +typedef volatile CPU_INT08U CPU_REG08; /* 8-bit register */ +typedef volatile CPU_INT16U CPU_REG16; /* 16-bit register */ +typedef volatile CPU_INT32U CPU_REG32; /* 32-bit register */ +typedef volatile CPU_INT64U CPU_REG64; /* 64-bit register */ + + +typedef void (*CPU_FNCT_VOID)(void); /* See Note #2a. */ +typedef void (*CPU_FNCT_PTR )(void *p_obj); /* See Note #2b. */ + + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE, CPU_CFG_DATA_SIZE, & CPU_CFG_DATA_SIZE_MAX with CPU's &/or +* compiler's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* Define CPU word sizes (see Note #1) : */ +#define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_32 /* Defines CPU address word size (in octets). */ +#define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_32 /* Defines CPU data word size (in octets). */ +#define CPU_CFG_DATA_SIZE_MAX CPU_WORD_SIZE_64 /* Defines CPU maximum word size (in octets). */ + +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_LITTLE /* Defines CPU data word-memory order (see Note #2). */ + + +/* +********************************************************************************************************* +* CONFIGURE CPU ADDRESS & DATA TYPES +********************************************************************************************************* +*/ + + /* CPU address type based on address bus size. */ +#if (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_ADDR; +#elif (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_ADDR; +#else +typedef CPU_INT08U CPU_ADDR; +#endif + + /* CPU data type based on data bus size. */ +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_DATA; +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_DATA; +#else +typedef CPU_INT08U CPU_DATA; +#endif + + +typedef CPU_DATA CPU_ALIGN; /* Defines CPU data-word-alignment size. */ +typedef CPU_ADDR CPU_SIZE_T; /* Defines CPU standard 'size_t' size. */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +* +* (2) Configure CPU_CFG_STK_ALIGN_BYTES with the highest minimum alignement required for +* cpu stacks. +* +* (a) ARM Procedure Calls Standard requires an 8 bytes stack alignment. +********************************************************************************************************* +*/ + +#define CPU_CFG_STK_GROWTH CPU_STK_GROWTH_HI_TO_LO /* Defines CPU stack growth order (see Note #1). */ + +#define CPU_CFG_STK_ALIGN_BYTES (8u) /* Defines CPU stack alignment in bytes. (see Note #2). */ + +typedef CPU_INT32U CPU_STK; /* Defines CPU stack data type. */ +typedef CPU_ADDR CPU_STK_SIZE; /* Defines CPU stack size data type. */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable should be declared via the CPU_SR_ALLOC() macro which, if +* used, MUST be declared following ALL other local variables. +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + /* Configure CPU critical method (see Note #1) : */ +#define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_STATUS_LOCAL + +typedef CPU_INT32U CPU_SR; /* Defines CPU status register size (see Note #3b). */ + + /* Allocates CPU status register word (see Note #3a). */ +#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) +#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 +#else +#define CPU_SR_ALLOC() +#endif + /* Save CPU current BASEPRI priority lvl for exception. */ +#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(CPU_CFG_KA_IPL_BOUNDARY << (8u - CPU_CFG_NVIC_PRIO_BITS));} while (0) +#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0) /* Restore CPU BASEPRI priority level. */ + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + /* Disable interrupts, ... */ + /* & start interrupts disabled time measurement.*/ +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \ + CPU_IntDisMeasStart(); } while (0) + /* Stop & measure interrupts disabled time, */ + /* ... & re-enable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \ + CPU_INT_EN(); } while (0) + +#else + +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) /* Disable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0) /* Re-enable interrupts. */ + +#endif + + +/* +********************************************************************************************************* +* MEMORY BARRIERS CONFIGURATION +* +* Note(s) : (1) (a) Configure memory barriers if required by the architecture. +* +* CPU_MB Full memory barrier. +* CPU_RMB Read (Loads) memory barrier. +* CPU_WMB Write (Stores) memory barrier. +* +********************************************************************************************************* +*/ + +#define CPU_MB() __asm__ __volatile__ ("dsb" : : : "memory") +#define CPU_RMB() __asm__ __volatile__ ("dsb" : : : "memory") +#define CPU_WMB() __asm__ __volatile__ ("dsb" : : : "memory") + + +/* +********************************************************************************************************* +* CPU COUNT ZEROS CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_LEAD_ZEROS_ASM_PRESENT to define count leading zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +* +* (b) Configure CPU_CFG_TRAIL_ZEROS_ASM_PRESENT to define count trailing zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +********************************************************************************************************* +*/ + + /* Configure CPU count leading zeros bits ... */ +#define CPU_CFG_LEAD_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1a). */ + + /* Configure CPU count trailing zeros bits ... */ +#define CPU_CFG_TRAIL_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1b). */ + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void CPU_IntDis (void); +void CPU_IntEn (void); + +void CPU_IntSrcDis (CPU_INT08U pos); +void CPU_IntSrcEn (CPU_INT08U pos); +void CPU_IntSrcPendClr(CPU_INT08U pos); +CPU_INT16S CPU_IntSrcPrioGet(CPU_INT08U pos); +void CPU_IntSrcPrioSet(CPU_INT08U pos, + CPU_INT08U prio, + CPU_INT08U type); + + +CPU_SR CPU_SR_Save (CPU_SR new_basepri); +void CPU_SR_Restore (CPU_SR cpu_sr); + + +void CPU_WaitForInt (void); +void CPU_WaitForExcept(void); + + +CPU_DATA CPU_RevBits (CPU_DATA val); + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr); +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr); + + +/* +********************************************************************************************************* +* INTERRUPT SOURCES +********************************************************************************************************* +*/ + +#define CPU_INT_STK_PTR 0u +#define CPU_INT_RESET 1u +#define CPU_INT_NMI 2u +#define CPU_INT_HFAULT 3u +#define CPU_INT_MEM 4u +#define CPU_INT_BUSFAULT 5u +#define CPU_INT_USAGEFAULT 6u +#define CPU_INT_RSVD_07 7u +#define CPU_INT_RSVD_08 8u +#define CPU_INT_RSVD_09 9u +#define CPU_INT_RSVD_10 10u +#define CPU_INT_SVCALL 11u +#define CPU_INT_DBGMON 12u +#define CPU_INT_RSVD_13 13u +#define CPU_INT_PENDSV 14u +#define CPU_INT_SYSTICK 15u +#define CPU_INT_EXT0 16u + + +/* +********************************************************************************************************* +* INTERRUPT TYPE +********************************************************************************************************* +*/ + +#define CPU_INT_KA 0u /* Kernel Aware interrupt request. */ +#define CPU_INT_NKA 1u /* Non-Kernel Aware interrupt request. */ + + +/* +********************************************************************************************************* +* CPU REGISTERS +********************************************************************************************************* +*/ + /* -------- SYSTICK REGISTERS --------- */ +#define CPU_REG_SYST_CSR (*((CPU_REG32 *)(0xE000E010))) /* SysTick Ctrl & Status Reg. */ +#define CPU_REG_SYST_RVR (*((CPU_REG32 *)(0xE000E014))) /* SysTick Reload Value Reg. */ +#define CPU_REG_SYST_CVR (*((CPU_REG32 *)(0xE000E018))) /* SysTick Current Value Reg. */ +#define CPU_REG_SYST_CALIB (*((CPU_REG32 *)(0xE000E01C))) /* SysTick Calibration Value Reg. */ + + /* ---------- NVIC REGISTERS ---------- */ +#define CPU_REG_NVIC_ISER(n) (*((CPU_REG32 *)(0xE000E100 + (n) * 4u))) /* IRQ Set En Reg. */ +#define CPU_REG_NVIC_ICER(n) (*((CPU_REG32 *)(0xE000E180 + (n) * 4u))) /* IRQ Clr En Reg. */ +#define CPU_REG_NVIC_ISPR(n) (*((CPU_REG32 *)(0xE000E200 + (n) * 4u))) /* IRQ Set Pending Reg. */ +#define CPU_REG_NVIC_ICPR(n) (*((CPU_REG32 *)(0xE000E280 + (n) * 4u))) /* IRQ Clr Pending Reg. */ +#define CPU_REG_NVIC_IABR(n) (*((CPU_REG32 *)(0xE000E300 + (n) * 4u))) /* IRQ Active Reg. */ +#define CPU_REG_NVIC_IPR(n) (*((CPU_REG32 *)(0xE000E400 + (n) * 4u))) /* IRQ Prio Reg. */ + + /* -- SYSTEM CONTROL BLOCK(SCB) REG -- */ +#define CPU_REG_SCB_CPUID (*((CPU_REG32 *)(0xE000ED00))) /* CPUID Base Reg. */ +#define CPU_REG_SCB_ICSR (*((CPU_REG32 *)(0xE000ED04))) /* Int Ctrl State Reg. */ +#define CPU_REG_SCB_VTOR (*((CPU_REG32 *)(0xE000ED08))) /* Vect Tbl Offset Reg. */ +#define CPU_REG_SCB_AIRCR (*((CPU_REG32 *)(0xE000ED0C))) /* App Int/Reset Ctrl Reg. */ +#define CPU_REG_SCB_SCR (*((CPU_REG32 *)(0xE000ED10))) /* System Ctrl Reg. */ +#define CPU_REG_SCB_CCR (*((CPU_REG32 *)(0xE000ED14))) /* Cfg Ctrl Reg. */ +#define CPU_REG_SCB_SHPRI1 (*((CPU_REG32 *)(0xE000ED18))) /* System Handlers 4 to 7 Prio. */ +#define CPU_REG_SCB_SHPRI2 (*((CPU_REG32 *)(0xE000ED1C))) /* System Handlers 8 to 11 Prio. */ +#define CPU_REG_SCB_SHPRI3 (*((CPU_REG32 *)(0xE000ED20))) /* System Handlers 12 to 15 Prio. */ +#define CPU_REG_SCB_SHCSR (*((CPU_REG32 *)(0xE000ED24))) /* System Handler Ctrl & State Reg. */ +#define CPU_REG_SCB_CFSR (*((CPU_REG32 *)(0xE000ED28))) /* Configurable Fault Status Reg. */ +#define CPU_REG_SCB_HFSR (*((CPU_REG32 *)(0xE000ED2C))) /* Hard Fault Status Reg. */ +#define CPU_REG_SCB_DFSR (*((CPU_REG32 *)(0xE000ED30))) /* Debug Fault Status Reg. */ +#define CPU_REG_SCB_MMFAR (*((CPU_REG32 *)(0xE000ED34))) /* Mem Manage Addr Reg. */ +#define CPU_REG_SCB_BFAR (*((CPU_REG32 *)(0xE000ED38))) /* Bus Fault Addr Reg. */ +#define CPU_REG_SCB_AFSR (*((CPU_REG32 *)(0xE000ED3C))) /* Aux Fault Status Reg. */ +#define CPU_REG_SCB_CPACR (*((CPU_REG32 *)(0xE000ED88))) /* Coprocessor Access Control Reg. */ + + /* ----- SCB REG FOR FP EXTENSION ----- */ +#define CPU_REG_SCB_FPCCR (*((CPU_REG32 *)(0xE000EF34))) /* Floating-Point Context Control Reg. */ +#define CPU_REG_SCB_FPCAR (*((CPU_REG32 *)(0xE000EF38))) /* Floating-Point Context Address Reg. */ +#define CPU_REG_SCB_FPDSCR (*((CPU_REG32 *)(0xE000EF3C))) /* FP Default Status Control Reg. */ + + /* ---------- CPUID REGISTERS --------- */ +#define CPU_REG_CPUID_PFR0 (*((CPU_REG32 *)(0xE000ED40))) /* Processor Feature Reg 0. */ +#define CPU_REG_CPUID_PFR1 (*((CPU_REG32 *)(0xE000ED44))) /* Processor Feature Reg 1. */ +#define CPU_REG_CPUID_DFR0 (*((CPU_REG32 *)(0xE000ED48))) /* Debug Feature Reg 0. */ +#define CPU_REG_CPUID_AFR0 (*((CPU_REG32 *)(0xE000ED4C))) /* Aux Feature Reg 0. */ +#define CPU_REG_CPUID_MMFR0 (*((CPU_REG32 *)(0xE000ED50))) /* Memory Model Feature Reg 0. */ +#define CPU_REG_CPUID_MMFR1 (*((CPU_REG32 *)(0xE000ED54))) /* Memory Model Feature Reg 1. */ +#define CPU_REG_CPUID_MMFR2 (*((CPU_REG32 *)(0xE000ED58))) /* Memory Model Feature Reg 2. */ +#define CPU_REG_CPUID_MMFR3 (*((CPU_REG32 *)(0xE000ED5C))) /* Memory Model Feature Reg 3. */ +#define CPU_REG_CPUID_ISAFR0 (*((CPU_REG32 *)(0xE000ED60))) /* ISA Feature Reg 0. */ +#define CPU_REG_CPUID_ISAFR1 (*((CPU_REG32 *)(0xE000ED64))) /* ISA Feature Reg 1. */ +#define CPU_REG_CPUID_ISAFR2 (*((CPU_REG32 *)(0xE000ED68))) /* ISA Feature Reg 2. */ +#define CPU_REG_CPUID_ISAFR3 (*((CPU_REG32 *)(0xE000ED6C))) /* ISA Feature Reg 3. */ +#define CPU_REG_CPUID_ISAFR4 (*((CPU_REG32 *)(0xE000ED70))) /* ISA Feature Reg 4. */ + + /* ----------- MPU REGISTERS ---------- */ +#define CPU_REG_MPU_TYPE (*((CPU_REG32 *)(0xE000ED90))) /* MPU Type Reg. */ +#define CPU_REG_MPU_CTRL (*((CPU_REG32 *)(0xE000ED94))) /* MPU Ctrl Reg. */ +#define CPU_REG_MPU_RNR (*((CPU_REG32 *)(0xE000ED98))) /* MPU Region Nbr Reg. */ +#define CPU_REG_MPU_RBAR (*((CPU_REG32 *)(0xE000ED9C))) /* MPU Region Base Addr Reg. */ +#define CPU_REG_MPU_RASR (*((CPU_REG32 *)(0xE000EDA0))) /* MPU Region Attrib & Size Reg. */ + + /* ----- REGISTERS NOT IN THE SCB ----- */ +#define CPU_REG_ICTR (*((CPU_REG32 *)(0xE000E004))) /* Int Ctrl'er Type Reg. */ +#define CPU_REG_DHCSR (*((CPU_REG32 *)(0xE000EDF0))) /* Debug Halting Ctrl & Status Reg. */ +#define CPU_REG_DCRSR (*((CPU_REG32 *)(0xE000EDF4))) /* Debug Core Reg Selector Reg. */ +#define CPU_REG_DCRDR (*((CPU_REG32 *)(0xE000EDF8))) /* Debug Core Reg Data Reg. */ +#define CPU_REG_DEMCR (*((CPU_REG32 *)(0xE000EDFC))) /* Debug Except & Monitor Ctrl Reg. */ +#define CPU_REG_STIR (*((CPU_REG32 *)(0xE000EF00))) /* Software Trigger Int Reg. */ + + +/* +********************************************************************************************************* +* CPU REGISTER BITS +********************************************************************************************************* +*/ + + /* ---------- SYSTICK CTRL & STATUS REG BITS ---------- */ +#define CPU_REG_SYST_CSR_COUNTFLAG 0x00010000 +#define CPU_REG_SYST_CSR_CLKSOURCE 0x00000004 +#define CPU_REG_SYST_CSR_TICKINT 0x00000002 +#define CPU_REG_SYST_CSR_ENABLE 0x00000001 + + /* -------- SYSTICK CALIBRATION VALUE REG BITS -------- */ +#define CPU_REG_SYST_CALIB_NOREF 0x80000000 +#define CPU_REG_SYST_CALIB_SKEW 0x40000000 + + /* -------------- INT CTRL STATE REG BITS ------------- */ +#define CPU_REG_SCB_ICSR_NMIPENDSET 0x80000000 +#define CPU_REG_SCB_ICSR_PENDSVSET 0x10000000 +#define CPU_REG_SCB_ICSR_PENDSVCLR 0x08000000 +#define CPU_REG_SCB_ICSR_PENDSTSET 0x04000000 +#define CPU_REG_SCB_ICSR_PENDSTCLR 0x02000000 +#define CPU_REG_SCB_ICSR_ISRPREEMPT 0x00800000 +#define CPU_REG_SCB_ICSR_ISRPENDING 0x00400000 +#define CPU_REG_SCB_ICSR_RETTOBASE 0x00000800 + + /* ------------- VECT TBL OFFSET REG BITS ------------- */ +#define CPU_REG_SCB_VTOR_TBLBASE 0x20000000 + + /* ------------ APP INT/RESET CTRL REG BITS ----------- */ +#define CPU_REG_SCB_AIRCR_ENDIANNESS 0x00008000 +#define CPU_REG_SCB_AIRCR_SYSRESETREQ 0x00000004 +#define CPU_REG_SCB_AIRCR_VECTCLRACTIVE 0x00000002 +#define CPU_REG_SCB_AIRCR_VECTRESET 0x00000001 + + /* --------------- SYSTEM CTRL REG BITS --------------- */ +#define CPU_REG_SCB_SCR_SEVONPEND 0x00000010 +#define CPU_REG_SCB_SCR_SLEEPDEEP 0x00000004 +#define CPU_REG_SCB_SCR_SLEEPONEXIT 0x00000002 + + /* ----------------- CFG CTRL REG BITS ---------------- */ +#define CPU_REG_SCB_CCR_STKALIGN 0x00000200 +#define CPU_REG_SCB_CCR_BFHFNMIGN 0x00000100 +#define CPU_REG_SCB_CCR_DIV_0_TRP 0x00000010 +#define CPU_REG_SCB_CCR_UNALIGN_TRP 0x00000008 +#define CPU_REG_SCB_CCR_USERSETMPEND 0x00000002 +#define CPU_REG_SCB_CCR_NONBASETHRDENA 0x00000001 + + /* ------- SYSTEM HANDLER CTRL & STATE REG BITS ------- */ +#define CPU_REG_SCB_SHCSR_USGFAULTENA 0x00040000 +#define CPU_REG_SCB_SHCSR_BUSFAULTENA 0x00020000 +#define CPU_REG_SCB_SHCSR_MEMFAULTENA 0x00010000 +#define CPU_REG_SCB_SHCSR_SVCALLPENDED 0x00008000 +#define CPU_REG_SCB_SHCSR_BUSFAULTPENDED 0x00004000 +#define CPU_REG_SCB_SHCSR_MEMFAULTPENDED 0x00002000 +#define CPU_REG_SCB_SHCSR_USGFAULTPENDED 0x00001000 +#define CPU_REG_SCB_SHCSR_SYSTICKACT 0x00000800 +#define CPU_REG_SCB_SHCSR_PENDSVACT 0x00000400 +#define CPU_REG_SCB_SHCSR_MONITORACT 0x00000100 +#define CPU_REG_SCB_SHCSR_SVCALLACT 0x00000080 +#define CPU_REG_SCB_SHCSR_USGFAULTACT 0x00000008 +#define CPU_REG_SCB_SHCSR_BUSFAULTACT 0x00000002 +#define CPU_REG_SCB_SHCSR_MEMFAULTACT 0x00000001 + + /* -------- CONFIGURABLE FAULT STATUS REG BITS -------- */ +#define CPU_REG_SCB_CFSR_DIVBYZERO 0x02000000 +#define CPU_REG_SCB_CFSR_UNALIGNED 0x01000000 +#define CPU_REG_SCB_CFSR_NOCP 0x00080000 +#define CPU_REG_SCB_CFSR_INVPC 0x00040000 +#define CPU_REG_SCB_CFSR_INVSTATE 0x00020000 +#define CPU_REG_SCB_CFSR_UNDEFINSTR 0x00010000 +#define CPU_REG_SCB_CFSR_BFARVALID 0x00008000 +#define CPU_REG_SCB_CFSR_STKERR 0x00001000 +#define CPU_REG_SCB_CFSR_UNSTKERR 0x00000800 +#define CPU_REG_SCB_CFSR_IMPRECISERR 0x00000400 +#define CPU_REG_SCB_CFSR_PRECISERR 0x00000200 +#define CPU_REG_SCB_CFSR_IBUSERR 0x00000100 +#define CPU_REG_SCB_CFSR_MMARVALID 0x00000080 +#define CPU_REG_SCB_CFSR_MSTKERR 0x00000010 +#define CPU_REG_SCB_CFSR_MUNSTKERR 0x00000008 +#define CPU_REG_SCB_CFSR_DACCVIOL 0x00000002 +#define CPU_REG_SCB_CFSR_IACCVIOL 0x00000001 + + /* ------------ HARD FAULT STATUS REG BITS ------------ */ +#define CPU_REG_SCB_HFSR_DEBUGEVT 0x80000000 +#define CPU_REG_SCB_HFSR_FORCED 0x40000000 +#define CPU_REG_SCB_HFSR_VECTTBL 0x00000002 + + /* ------------ DEBUG FAULT STATUS REG BITS ----------- */ +#define CPU_REG_SCB_DFSR_EXTERNAL 0x00000010 +#define CPU_REG_SCB_DFSR_VCATCH 0x00000008 +#define CPU_REG_SCB_DFSR_DWTTRAP 0x00000004 +#define CPU_REG_SCB_DFSR_BKPT 0x00000002 +#define CPU_REG_SCB_DFSR_HALTED 0x00000001 + + /* -------- COPROCESSOR ACCESS CONTROL REG BITS ------- */ +#define CPU_REG_SCB_CPACR_CP10_FULL_ACCESS 0x00300000 +#define CPU_REG_SCB_CPACR_CP11_FULL_ACCESS 0x00C00000 + + +/* +********************************************************************************************************* +* CPU REGISTER MASK +********************************************************************************************************* +*/ + +#define CPU_MSK_SCB_ICSR_VECT_ACTIVE 0x000001FF + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_ADDR_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + + +#if (CPU_CFG_DATA_SIZE_MAX < CPU_CFG_DATA_SIZE) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be >= CPU_CFG_DATA_SIZE]" +#endif + + + + +#ifndef CPU_CFG_ENDIAN_TYPE +#error "CPU_CFG_ENDIAN_TYPE not #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" + +#elif ((CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_BIG ) && \ + (CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_LITTLE)) +#error "CPU_CFG_ENDIAN_TYPE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" +#endif + + + + +#ifndef CPU_CFG_STK_GROWTH +#error "CPU_CFG_STK_GROWTH not #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" + +#elif ((CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_LO_TO_HI) && \ + (CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_HI_TO_LO)) +#error "CPU_CFG_STK_GROWTH illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" +#endif + + + + +#ifndef CPU_CFG_CRITICAL_METHOD +#error "CPU_CFG_CRITICAL_METHOD not #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" + +#elif ((CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_INT_DIS_EN ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_STK ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_LOCAL)) +#error "CPU_CFG_CRITICAL_METHOD illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu.h MODULE'. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* End of CPU module include. */ + diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_a.s b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_a.s new file mode 100644 index 00000000..03b57af1 --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_a.s @@ -0,0 +1,295 @@ +@******************************************************************************************************** +@ uC/CPU +@ CPU CONFIGURATION & PORT LAYER +@ +@ Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + +@******************************************************************************************************** +@ +@ CPU PORT FILE +@ +@ ARMv7-M +@ GNU C Compiler +@ +@ Filename : cpu_a.s +@ Version : v1.32.00 +@******************************************************************************************************** +@ Note(s) : This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + + .global CPU_IntDis + .global CPU_IntEn + + .global CPU_SR_Save + .global CPU_SR_Restore + + .global CPU_WaitForInt + .global CPU_WaitForExcept + + + .global CPU_CntLeadZeros + .global CPU_CntTrailZeros + .global CPU_RevBits + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + +.text +.align 2 +.syntax unified + + +@******************************************************************************************************** +@ DISABLE and ENABLE INTERRUPTS +@ +@ Description : Disable/Enable interrupts. +@ +@ Prototypes : void CPU_IntDis(void); +@ void CPU_IntEn (void); +@******************************************************************************************************** + +.thumb_func +CPU_IntDis: + CPSID I + BX LR + +.thumb_func +CPU_IntEn: + CPSIE I + BX LR + + +@******************************************************************************************************** +@ CRITICAL SECTION FUNCTIONS +@ +@ Description : Disable/Enable Kernel aware interrupts by preserving the state of BASEPRI. Generally speaking, +@ the state of the BASEPRI interrupt exception processing is stored in the local variable +@ 'cpu_sr' & Kernel Aware interrupts are then disabled ('cpu_sr' is allocated in all functions +@ that need to disable Kernel aware interrupts). The previous BASEPRI interrupt state is restored +@ by copying 'cpu_sr' into the BASEPRI register. +@ +@ Prototypes : CPU_SR CPU_SR_Save (CPU_SR new_basepri); +@ void CPU_SR_Restore(CPU_SR cpu_sr); +@ +@ Note(s) : (1) These functions are used in general like this : +@ +@ void Task (void *p_arg) +@ { +@ CPU_SR_ALLOC(); /* Allocate storage for CPU status register */ +@ : +@ : +@ CPU_CRITICAL_ENTER(); /* cpu_sr = CPU_SR_Save(); */ +@ : +@ : +@ CPU_CRITICAL_EXIT(); /* CPU_SR_Restore(cpu_sr); */ +@ : +@ } +@ +@ (2) Increasing priority using a write to BASEPRI does not take effect immediately. +@ (a) IMPLICATION This erratum means that the instruction after an MSR to boost BASEPRI +@ might incorrectly be preempted by an insufficient high priority exception. +@ +@ (b) WORKAROUND The MSR to boost BASEPRI can be replaced by the following code sequence: +@ +@ CPSID i +@ MSR to BASEPRI +@ DSB +@ ISB +@ CPSIE i +@******************************************************************************************************** + +.thumb_func +CPU_SR_Save: + CPSID I @ Cortex-M7 errata notice. See Note #2 + PUSH {R1} + MRS R1, BASEPRI + MSR BASEPRI, R0 + DSB + ISB + MOV R0, R1 + POP {R1} + CPSIE I + BX LR + + +.thumb_func +CPU_SR_Restore: + CPSID I @ Cortex-M7 errata notice. See Note #2 + MSR BASEPRI, R0 + DSB + ISB + CPSIE I + BX LR + + +@******************************************************************************************************** +@ WAIT FOR INTERRUPT +@ +@ Description : Enters sleep state, which will be exited when an interrupt is received. +@ +@ Prototypes : void CPU_WaitForInt (void) +@ +@ Argument(s) : none. +@******************************************************************************************************** + +.thumb_func +CPU_WaitForInt: + WFI @ Wait for interrupt + BX LR + + +@******************************************************************************************************** +@ WAIT FOR EXCEPTION +@ +@ Description : Enters sleep state, which will be exited when an exception is received. +@ +@ Prototypes : void CPU_WaitForExcept (void) +@ +@ Argument(s) : none. +@******************************************************************************************************** + +.thumb_func +CPU_WaitForExcept: + WFE @ Wait for exception + BX LR + + +@******************************************************************************************************** +@ CPU_CntLeadZeros() +@ COUNT LEADING ZEROS +@ +@ Description : Counts the number of contiguous, most-significant, leading zero bits before the +@ first binary one bit in a data value. +@ +@ Prototype : CPU_DATA CPU_CntLeadZeros(CPU_DATA val); +@ +@ Argument(s) : val Data value to count leading zero bits. +@ +@ Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +@ +@ Note(s) : (1) (a) Supports 32-bit data value size as configured by 'CPU_DATA' (see 'cpu.h +@ CPU WORD CONFIGURATION Note #1'). +@ +@ (b) For 32-bit values : +@ +@ b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +@ --- --- --- --- --- --- --- --- --------------- +@ 1 x x x x x x x 0 +@ 0 1 x x x x x x 1 +@ 0 0 1 x x x x x 2 +@ : : : : : : : : : +@ : : : : : : : : : +@ 0 0 0 1 x x x x 27 +@ 0 0 0 0 1 x x x 28 +@ 0 0 0 0 0 1 x x 29 +@ 0 0 0 0 0 0 1 x 30 +@ 0 0 0 0 0 0 0 1 31 +@ 0 0 0 0 0 0 0 0 32 +@ +@ +@ (2) MUST be defined in 'cpu_a.asm' (or 'cpu_c.c') if CPU_CFG_LEAD_ZEROS_ASM_PRESENT is +@ #define'd in 'cpu_cfg.h' or 'cpu.h'. +@******************************************************************************************************** + +.thumb_func +CPU_CntLeadZeros: + CLZ R0, R0 @ Count leading zeros + BX LR + + +@******************************************************************************************************** +@ CPU_CntTrailZeros() +@ COUNT TRAILING ZEROS +@ +@ Description : Counts the number of contiguous, least-significant, trailing zero bits before the +@ first binary one bit in a data value. +@ +@ Prototype : CPU_DATA CPU_CntTrailZeros(CPU_DATA val); +@ +@ Argument(s) : val Data value to count trailing zero bits. +@ +@ Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +@ +@ Note(s) : (1) (a) Supports 32-bit data value size as configured by 'CPU_DATA' (see 'cpu.h +@ CPU WORD CONFIGURATION Note #1'). +@ +@ (b) For 32-bit values : +@ +@ b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +@ --- --- --- --- --- --- --- --- ---------------- +@ x x x x x x x 1 0 +@ x x x x x x 1 0 1 +@ x x x x x 1 0 0 2 +@ : : : : : : : : : +@ : : : : : : : : : +@ x x x x 1 0 0 0 27 +@ x x x 1 0 0 0 0 28 +@ x x 1 0 0 0 0 0 29 +@ x 1 0 0 0 0 0 0 30 +@ 1 0 0 0 0 0 0 0 31 +@ 0 0 0 0 0 0 0 0 32 +@ +@ +@ (2) MUST be defined in 'cpu_a.asm' (or 'cpu_c.c') if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT is +@ #define'd in 'cpu_cfg.h' or 'cpu.h'. +@******************************************************************************************************** + +.thumb_func +CPU_CntTrailZeros: + RBIT R0, R0 @ Reverse bits + CLZ R0, R0 @ Count trailing zeros + BX LR + + +@******************************************************************************************************** +@ CPU_RevBits() +@ REVERSE BITS +@ +@ Description : Reverses the bits in a data value. +@ +@ Prototypes : CPU_DATA CPU_RevBits(CPU_DATA val); +@ +@ Argument(s) : val Data value to reverse bits. +@ +@ Return(s) : Value with all bits in 'val' reversed (see Note #1). +@ +@ Note(s) : (1) The final, reversed data value for 'val' is such that : +@ +@ 'val's final bit 0 = 'val's original bit N +@ 'val's final bit 1 = 'val's original bit (N - 1) +@ 'val's final bit 2 = 'val's original bit (N - 2) +@ +@ ... ... +@ +@ 'val's final bit (N - 2) = 'val's original bit 2 +@ 'val's final bit (N - 1) = 'val's original bit 1 +@ 'val's final bit N = 'val's original bit 0 +@******************************************************************************************************** + +.thumb_func +CPU_RevBits: + RBIT R0, R0 @ Reverse bits + BX LR + + +@******************************************************************************************************** +@ CPU ASSEMBLY PORT FILE END +@******************************************************************************************************** + +.end + diff --git a/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_c.c b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_c.c new file mode 100644 index 00000000..ccba7479 --- /dev/null +++ b/rtos/uC-CPU/ARM-Cortex-M/ARMv7-M/cpu_c.c @@ -0,0 +1,772 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* ARMv7-M +* +* Filename : cpu_c.c +* Version : v1.32.00 +********************************************************************************************************* +* Note(s) : This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + +#define CPU_INT_SRC_POS_MAX ((((CPU_REG_ICTR & 0xF) + 1) * 32) + 16) + +#define CPU_BIT_BAND_SRAM_REG_LO 0x20000000 +#define CPU_BIT_BAND_SRAM_REG_HI 0x200FFFFF +#define CPU_BIT_BAND_SRAM_BASE 0x22000000 + + +#define CPU_BIT_BAND_PERIPH_REG_LO 0x40000000 +#define CPU_BIT_BAND_PERIPH_REG_HI 0x400FFFFF +#define CPU_BIT_BAND_PERIPH_BASE 0x42000000 + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU_BitBandClr() +* +* Description : Clear bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandClr (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 0; + } +} + + +/* +********************************************************************************************************* +* CPU_BitBandSet() +* +* Description : Set bit in bit-band region. +* +* Argument(s) : addr Byte address in memory space. +* +* bit_nbr Bit number in byte. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_BitBandSet (CPU_ADDR addr, + CPU_INT08U bit_nbr) +{ + CPU_ADDR bit_word_off; + CPU_ADDR bit_word_addr; + + + if ((addr >= CPU_BIT_BAND_SRAM_REG_LO) && + (addr <= CPU_BIT_BAND_SRAM_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_SRAM_REG_LO ) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_SRAM_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + + } else if ((addr >= CPU_BIT_BAND_PERIPH_REG_LO) && + (addr <= CPU_BIT_BAND_PERIPH_REG_HI)) { + bit_word_off = ((addr - CPU_BIT_BAND_PERIPH_REG_LO) * 32) + (bit_nbr * 4); + bit_word_addr = CPU_BIT_BAND_PERIPH_BASE + bit_word_off; + + *(volatile CPU_INT32U *)(bit_word_addr) = 1; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcDis() +* +* Description : Disable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table : +* +* 0 Invalid (see Note #1a). +* 1 Invalid (see Note #1b). +* 2 Non-maskable Interrupt. +* 3 Hard Fault. +* 4 Memory Management. +* 5 Bus Fault. +* 6 Usage Fault. +* 7-10 Reserved. +* 11 SVCall. +* 12 Debug Monitor. +* 13 Reserved. +* 14 PendSV. +* 15 SysTick. +* 16+ External Interrupt. +* +* Return(s) : none. +* +* Note(s) : (1) Several table positions do not contain interrupt sources : +* +* (a) Position 0 contains the stack pointer. +* (b) Positions 7-10, 13 are reserved. +* +* (2) Several interrupts cannot be disabled/enabled : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) SVCall. +* (e) Debug monitor. +* (f) PendSV. +* +* (3) The maximum Cortex-M3, Cortex-M4, and Cortex-M7 table position is 256. A particular +* Cortex-M may have fewer than 240 external exceptions and, consequently, fewer than +* 256 table positions. This function assumes that the specified table position is valid +* if the interrupt controller type register's INTLINESNUM field is large enough so that +* the position COULD be valid. +********************************************************************************************************* +*/ + +void CPU_IntSrcDis (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT16U pos_max; + CPU_INT08U nbr; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR &= ~CPU_REG_SCB_SHCSR_MEMFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR &= ~CPU_REG_SCB_SHCSR_BUSFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR &= ~CPU_REG_SCB_SHCSR_USGFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SYST_CSR &= ~CPU_REG_SYST_CSR_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ICER(group) = DEF_BIT(nbr); /* Disable interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcEn() +* +* Description : Enable an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcDis() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcEn (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT16U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR |= CPU_REG_SCB_SHCSR_MEMFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR |= CPU_REG_SCB_SHCSR_BUSFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SCB_SHCSR |= CPU_REG_SCB_SHCSR_USGFAULTENA; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_ENABLE; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ISER(group) = DEF_BIT(nbr); /* Enable interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPendClr() +* +* Description : Clear a pending interrupt. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) The pending status of several interrupts cannot be clear/set : +* +* (a) Reset. +* (b) NMI. +* (c) Hard fault. +* (d) Memory Managment. +* (e) Bus Fault. +* (f) Usage Fault. +* (g) SVCall. +* (h) Debug monitor. +* (i) PendSV. +* (j) Systick +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +void CPU_IntSrcPendClr (CPU_INT08U pos) + +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT16U pos_max; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + case CPU_INT_MEM: /* Memory management (see Note #2). */ + case CPU_INT_SVCALL: /* SVCall (see Note #2). */ + case CPU_INT_DBGMON: /* Debug monitor (see Note #2). */ + case CPU_INT_PENDSV: /* PendSV (see Note #2). */ + case CPU_INT_BUSFAULT: /* Bus fault. */ + case CPU_INT_USAGEFAULT: /* Usage fault. */ + case CPU_INT_SYSTICK: /* SysTick. */ + break; + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 32; + nbr = (pos - 16) % 32; + + CPU_CRITICAL_ENTER(); + CPU_REG_NVIC_ICPR(group) = DEF_BIT(nbr); /* Clear Pending interrupt. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioSet() +* +* Description : Set priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* prio Priority. Use a lower priority number for a higher priority. +* +* type Kernel/Non-Kernel aware priority type. +* CPU_INT_KA Kernel Aware interrupt request. See Note #4 +* CPU_INT_NKA Non-Kernel Aware interrupt request. See Note #5 +* +* Return(s) : none. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) Several interrupts priorities CANNOT be set : +* +* (a) Reset (always -3). +* (b) NMI (always -2). +* (c) Hard fault (always -1). +* +* (3) See 'CPU_IntSrcDis() Note #3'. +* +* (4) A Kernel Aware ISR can make OS service calls in its handler (Mutex, Flags, etc.). +* It follows the template below: +* +* static void KA_ISR_Handler (void) +* { +* CPU_SR_ALLOC(); +* +* CPU_CRITICAL_ENTER(); +* OSIntEnter(); Tell OS we are starting an ISR +* CPU_CRITICAL_EXIT(); +* +* --------------- HANDLER YOUR ISR HERE --------------- +* +* OSIntExit(); Tell OS we are leaving the ISR +* } +* +* (5) A Non-Kernel Aware ISR must never make OS service calls. It follows the template below: +* +* static void NKA_ISR_Handler (void) +* { +* --------------- HANDLER YOUR ISR HERE --------------- +* } +********************************************************************************************************* +*/ + +void CPU_IntSrcPrioSet (CPU_INT08U pos, + CPU_INT08U prio, + CPU_INT08U type) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT16U pos_max; + CPU_INT32U temp; + CPU_INT32U prio_offset; + CPU_SR_ALLOC(); + + + prio_offset = (prio << (DEF_OCTET_NBR_BITS - CPU_CFG_NVIC_PRIO_BITS)); + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + break; + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (0 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (1 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (1 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (2 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI1 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI2; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI2 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_DBGMON: /* Debug monitor. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (0 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (0 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (2 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (2 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (3 * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (3 * DEF_OCTET_NBR_BITS)); + CPU_REG_SCB_SHPRI3 = temp; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + + if (type == CPU_INT_NKA) { /* Check if NKA priority goes beyond KA boundary */ + if (prio >= CPU_CFG_KA_IPL_BOUNDARY) { /* Priority must be < CPU_CFG_KA_IPL_BOUNDARY */ + CPU_SW_Exception(); + } + + } else { /* Check if KA priority is less than KA boundary */ + if (prio < CPU_CFG_KA_IPL_BOUNDARY) { /* Priority must be >= CPU_CFG_KA_IPL_BOUNDARY */ + CPU_SW_Exception(); + } + } + + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_IPR(group); + temp &= ~((CPU_INT32U)DEF_OCTET_MASK << (nbr * DEF_OCTET_NBR_BITS)); + temp |= ((CPU_INT32U)prio_offset << (nbr * DEF_OCTET_NBR_BITS)); + CPU_REG_NVIC_IPR(group) = temp; /* Set interrupt priority. */ + CPU_CRITICAL_EXIT(); + } + break; + } +} + + +/* +********************************************************************************************************* +* CPU_IntSrcPrioGet() +* +* Description : Get priority of an interrupt source. +* +* Argument(s) : pos Position of interrupt vector in interrupt table (see 'CPU_IntSrcDis()'). +* +* Return(s) : Priority of interrupt source. If the interrupt source specified is invalid, then +* DEF_INT_16S_MIN_VAL is returned. +* +* Note(s) : (1) See 'CPU_IntSrcDis() Note #1'. +* +* (2) See 'CPU_IntSrcPrioSet() Note #2'. +* +* (3) See 'CPU_IntSrcDis() Note #3'. +********************************************************************************************************* +*/ + +CPU_INT16S CPU_IntSrcPrioGet (CPU_INT08U pos) +{ + CPU_INT08U group; + CPU_INT08U nbr; + CPU_INT16U pos_max; + CPU_INT16S prio; + CPU_INT32U temp; + CPU_SR_ALLOC(); + + + switch (pos) { + case CPU_INT_STK_PTR: /* ---------------- INVALID OR RESERVED --------------- */ + case CPU_INT_RSVD_07: + case CPU_INT_RSVD_08: + case CPU_INT_RSVD_09: + case CPU_INT_RSVD_10: + case CPU_INT_RSVD_13: + prio = DEF_INT_16S_MIN_VAL; + break; + + + /* ----------------- SYSTEM EXCEPTIONS ---------------- */ + case CPU_INT_RESET: /* Reset (see Note #2). */ + prio = -3; + break; + + case CPU_INT_NMI: /* Non-maskable interrupt (see Note #2). */ + prio = -2; + break; + + case CPU_INT_HFAULT: /* Hard fault (see Note #2). */ + prio = -1; + break; + + + case CPU_INT_MEM: /* Memory management. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + prio = (temp >> (0 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + case CPU_INT_BUSFAULT: /* Bus fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + prio = (temp >> (1 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + case CPU_INT_USAGEFAULT: /* Usage fault. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI1; + prio = (temp >> (2 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SVCALL: /* SVCall. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI2; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_DBGMON: /* Debug monitor. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + prio = (temp >> (0 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_PENDSV: /* PendSV. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + prio = (temp >> (2 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + case CPU_INT_SYSTICK: /* SysTick. */ + CPU_CRITICAL_ENTER(); + temp = CPU_REG_SCB_SHPRI3; + prio = (temp >> (3 * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + CPU_CRITICAL_EXIT(); + break; + + + /* ---------------- EXTERNAL INTERRUPT ---------------- */ + default: + pos_max = CPU_INT_SRC_POS_MAX; + if (pos < pos_max) { /* See Note #3. */ + group = (pos - 16) / 4; + nbr = (pos - 16) % 4; + + CPU_CRITICAL_ENTER(); + temp = CPU_REG_NVIC_IPR(group); /* Read group interrupt priority. */ + CPU_CRITICAL_EXIT(); + + prio = (temp >> (nbr * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK; + } else { + prio = DEF_INT_16S_MIN_VAL; + } + break; + } + + if (prio != DEF_INT_16S_MIN_VAL) { + prio = (prio >> (DEF_OCTET_NBR_BITS - CPU_CFG_NVIC_PRIO_BITS)); + } + + return (prio); +} + +#ifdef __cplusplus +} +#endif diff --git a/rtos/uC-CPU/Cfg/cpu_cfg.h b/rtos/uC-CPU/Cfg/cpu_cfg.h new file mode 100644 index 00000000..a267d8d3 --- /dev/null +++ b/rtos/uC-CPU/Cfg/cpu_cfg.h @@ -0,0 +1,254 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU CONFIGURATION FILE +* +* TEMPLATE +* +* Filename : cpu_cfg.h +* Version : v1.32.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_MODULE_PRESENT +#define CPU_CFG_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU NAME CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_NAME_EN to enable/disable CPU host name feature : +* +* (a) CPU host name storage +* (b) CPU host name API functions +* +* (2) Configure CPU_CFG_NAME_SIZE with the desired ASCII string size of the CPU host name, +* including the terminating NULL character. +* +* See also 'cpu_core.h GLOBAL VARIABLES Note #1'. +********************************************************************************************************* +*/ + + /* Configure CPU host name feature (see Note #1) : */ +#define CPU_CFG_NAME_EN DEF_DISABLED + /* DEF_DISABLED CPU host name DISABLED */ + /* DEF_ENABLED CPU host name ENABLED */ + + /* Configure CPU host name ASCII string size ... */ +#define CPU_CFG_NAME_SIZE 16 /* ... (see Note #2). */ + + +/* +********************************************************************************************************* +* CPU TIMESTAMP CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_TS_xx_EN to enable/disable CPU timestamp features : +* +* (a) CPU_CFG_TS_32_EN enable/disable 32-bit CPU timestamp feature +* (b) CPU_CFG_TS_64_EN enable/disable 64-bit CPU timestamp feature +* +* (2) (a) Configure CPU_CFG_TS_TMR_SIZE with the CPU timestamp timer's word size : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (b) If the size of the CPU timestamp timer is not a binary multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple octet word +* size SHOULD be configured (e.g. to 16-bits). However, the minimum supported word +* size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2a'. +********************************************************************************************************* +*/ + + /* Configure CPU timestamp features (see Note #1) : */ +#define CPU_CFG_TS_32_EN DEF_DISABLED +#define CPU_CFG_TS_64_EN DEF_DISABLED + /* DEF_DISABLED CPU timestamps DISABLED */ + /* DEF_ENABLED CPU timestamps ENABLED */ + + /* Configure CPU timestamp timer word size ... */ + /* ... (see Note #2) : */ +#define CPU_CFG_TS_TMR_SIZE CPU_WORD_SIZE_32 + + +/* +********************************************************************************************************* +* CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_INT_DIS_MEAS_EN to enable/disable measuring CPU's interrupts +* disabled time : +* +* (a) Enabled, if CPU_CFG_INT_DIS_MEAS_EN #define'd in 'cpu_cfg.h' +* +* (b) Disabled, if CPU_CFG_INT_DIS_MEAS_EN NOT #define'd in 'cpu_cfg.h' +* +* See also 'cpu_core.h FUNCTION PROTOTYPES Note #1'. +* +* (b) Configure CPU_CFG_INT_DIS_MEAS_OVRHD_NBR with the number of times to measure & +* average the interrupts disabled time measurements overhead. +* +* See also 'cpu_core.c CPU_IntDisMeasInit() Note #3a'. +********************************************************************************************************* +*/ + +#if 0 /* Configure CPU interrupts disabled time ... */ +#define CPU_CFG_INT_DIS_MEAS_EN /* ... measurements feature (see Note #1a). */ +#endif + + /* Configure number of interrupts disabled overhead ... */ +#define CPU_CFG_INT_DIS_MEAS_OVRHD_NBR 1u /* ... time measurements (see Note #1b). */ + + +/* +********************************************************************************************************* +* CPU COUNT ZEROS CONFIGURATION +* +* Note(s) : (1) (a) Configure CPU_CFG_LEAD_ZEROS_ASM_PRESENT to define count leading zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +* +* (b) Configure CPU_CFG_TRAIL_ZEROS_ASM_PRESENT to define count trailing zeros bits +* function(s) in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) otherwise +********************************************************************************************************* +*/ + +#if 0 /* Configure CPU count leading zeros bits ... */ +#define CPU_CFG_LEAD_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1a). */ +#endif + +#if 0 /* Configure CPU count trailing zeros bits ... */ +#define CPU_CFG_TRAIL_ZEROS_ASM_PRESENT /* ... assembly-version (see Note #1b). */ +#endif + + +/* +********************************************************************************************************* +* CPU ENDIAN TYPE OVERRIDE +* +* Note(s) : (1) Configure CPU_CFG_ENDIAN_TYPE to override the default CPU endian type defined in cpu.h. +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +* +* (2) Defining CPU_CFG_ENDIAN_TYPE here is only valid for supported bi-endian architectures. +* See 'cpu.h CPU WORD CONFIGURATION Note #3' for details +********************************************************************************************************* +*/ + +#if 0 +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_BIG /* Defines CPU data word-memory order (see Note #2). */ +#endif + + +/* +********************************************************************************************************* +* CACHE MANAGEMENT +* +* Note(s) : (1) Configure CPU_CFG_CACHE_MGMT_EN to enable the cache management API. +* +* (2) This option only enables the cache management functions. +* It does not enable any hardware caches, which should be configured in startup code. +* Caches must be configured and enabled by the time CPU_Init() is called. +* +* (3) This option is usually required for device drivers which use a DMA engine to transmit +* buffers that are located in cached memory. +********************************************************************************************************* +*/ + +#define CPU_CFG_CACHE_MGMT_EN DEF_DISABLED /* Defines CPU data word-memory order (see Note #1). */ + + +/* +********************************************************************************************************* +* KERNEL AWARE IPL BOUNDARY +* +* Note(s) : (1) Determines the IPL level that establishes the boundary for ISRs that are kernel-aware and +* those that are not. All ISRs at this level or lower are kernel-aware. +* +* (2) ARMv7-M: Since the port is using BASEPRI to separate kernel vs non-kernel aware ISR, please +* make sure your external interrupt priorities are set accordingly. For example, if +* CPU_CFG_KA_IPL_BOUNDARY is set to 4 then external interrupt priorities 4-15 will be kernel +* aware while priorities 0-3 will be use as non-kernel aware. +********************************************************************************************************* +*/ + +#define CPU_CFG_KA_IPL_BOUNDARY 4u + + +/* +********************************************************************************************************* +* ARM CORTEX-M +* +* Note(s) : (1) Determines the interrupt programmable priority levels. This is normally specified in the +* Microcontroller reference manual. 4-bits gives us 16 programmable priority levels. +* +* Example 1 Example 2 +* NVIC_IPRx NVIC_IPRx +* 7 0 7 0 +* +------------------+ +------------------+ +* | PRIO | | PRIO | +* +------------------+ +------------------+ +* +* Bits[7:4] Priority mask bits Bits[7:6] Priority mask bits +* Bits[3:0] Reserved Bits[5:0] Reserved +* +* Example 1: CPU_CFG_NVIC_PRIO_BITS should be set to 4 due to the processor +* implementing only bits[7:4]. +* +* Example 2: CPU_CFG_NVIC_PRIO_BITS should be set to 2 due to the processor +* implementing only bits[7:6]. +********************************************************************************************************* +*/ +#if 0 +#define CPU_CFG_NVIC_PRIO_BITS 4u +#endif + + +/* +********************************************************************************************************* +* MODULE END +********************************************************************************************************* +*/ + +#endif /* End of CPU cfg module include. */ + diff --git a/rtos/uC-CPU/LICENSE b/rtos/uC-CPU/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/rtos/uC-CPU/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/rtos/uC-CPU/NOTICE b/rtos/uC-CPU/NOTICE new file mode 100644 index 00000000..e8cacd2c --- /dev/null +++ b/rtos/uC-CPU/NOTICE @@ -0,0 +1,28 @@ +ATTENTION ALL USERS OF THIS REPOSITORY: + +The original work found in this repository is provided by Silicon Labs under the +Apache License, Version 2.0. + +Any third party may contribute derivative works to the original work in which +modifications are clearly identified as being licensed under: + + (1) the Apache License, Version 2.0 or a compatible open source license; or + (2) under a proprietary license with a copy of such license deposited. + +All posted derivative works must clearly identify which license choice has been +elected. + +No such posted derivative works will be considered to be a “Contribution” under +the Apache License, Version 2.0. + +SILICON LABS MAKES NO WARRANTY WITH RESPECT TO ALL POSTED THIRD PARTY CONTENT +AND DISCLAIMS ALL OTHER WARRANTIES OR LIABILITIES, INCLUDING ALL WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OWNERSHIP, +NON-INFRINGEMENT, AND NON-MISAPPROPRIATION. + +In the event a derivative work is desired to be submitted to Silicon Labs as a +“Contribution” under the Apache License, Version 2.0, a “Contributor” must give +written email notice to micrium@weston-embedded.com. Unless an email response in +the affirmative to accept the derivative work as a “Contribution”, such email +submission should be considered to have not been incorporated into the original +work. diff --git a/rtos/uC-CPU/Posix/cpu.h b/rtos/uC-CPU/Posix/cpu.h new file mode 100644 index 00000000..d276253b --- /dev/null +++ b/rtos/uC-CPU/Posix/cpu.h @@ -0,0 +1,535 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* Linux i86pc & amd64 +* GNU Toolchain +* +* Filename : cpu.h +* Version : v1.32.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU header file is protected from multiple pre-processor inclusion through use of +* the CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_MODULE_PRESENT /* See Note #1. */ +#define CPU_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CPU INCLUDE FILES +* +* Note(s) : (1) The following CPU files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_def.h +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (2) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (3) Since NO custom library modules are included, 'cpu.h' may ONLY use configurations from +* CPU configuration file 'cpu_cfg.h' that do NOT reference any custom library definitions. +* +* In other words, 'cpu.h' may use 'cpu_cfg.h' configurations that are #define'd to numeric +* constants or to NULL (i.e. NULL-valued #define's); but may NOT use configurations to +* custom library #define's (e.g. DEF_DISABLED or DEF_ENABLED). +********************************************************************************************************* +*/ + +#include +#include +#include + +#include +#include /* See Note #3. */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* CONFIGURE STANDARD DATA TYPES +* +* Note(s) : (1) Configure standard data types according to CPU-/compiler-specifications. +* +* (2) (a) (1) 'CPU_FNCT_VOID' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has no arguments. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_VOID FnctName; +* +* FnctName(); +* +* (b) (1) 'CPU_FNCT_PTR' data type defined to replace the commonly-used function pointer +* data type of a pointer to a function which returns void & has a single void +* pointer argument. +* +* (2) Example function pointer usage : +* +* CPU_FNCT_PTR FnctName; +* void *p_obj +* +* FnctName(p_obj); +********************************************************************************************************* +*/ + +typedef void CPU_VOID; +typedef char CPU_CHAR; /* 8-bit character */ +typedef uint8_t CPU_BOOLEAN; /* 8-bit boolean or logical */ +typedef uint8_t CPU_INT08U; /* 8-bit unsigned integer */ +typedef int8_t CPU_INT08S; /* 8-bit signed integer */ +typedef uint16_t CPU_INT16U; /* 16-bit unsigned integer */ +typedef int16_t CPU_INT16S; /* 16-bit signed integer */ +typedef uint32_t CPU_INT32U; /* 32-bit unsigned integer */ +typedef int32_t CPU_INT32S; /* 32-bit signed integer */ +typedef uint64_t CPU_INT64U; /* 64-bit unsigned integer */ +typedef int64_t CPU_INT64S; /* 64-bit signed integer */ + +typedef float CPU_FP32; /* 32-bit floating point */ +typedef double CPU_FP64; /* 64-bit floating point */ + + +typedef volatile CPU_INT08U CPU_REG08; /* 8-bit register */ +typedef volatile CPU_INT16U CPU_REG16; /* 16-bit register */ +typedef volatile CPU_INT32U CPU_REG32; /* 32-bit register */ +typedef volatile CPU_INT64U CPU_REG64; /* 64-bit register */ + + +typedef void (*CPU_FNCT_VOID)(void); /* See Note #2a. */ +typedef void (*CPU_FNCT_PTR )(void *p_obj); /* See Note #2b. */ + + + +typedef struct CPU_Interrupt CPU_INTERRUPT; + +struct CPU_Interrupt { + void (*ISR_Fnct)(void); + CPU_INT08U Prio; + CPU_BOOLEAN En; + CPU_CHAR *NamePtr; + CPU_BOOLEAN TraceEn; +}; + + +typedef struct CPU_Tmr_Interrupt CPU_TMR_INTERRUPT; + +struct CPU_Tmr_Interrupt { + CPU_INTERRUPT Interrupt; + CPU_BOOLEAN OneShot; + CPU_INT32U PeriodSec; + CPU_INT32U PeriodMuSec; +}; + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE, CPU_CFG_DATA_SIZE, & CPU_CFG_DATA_SIZE_MAX with CPU's &/or +* compiler's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* Define CPU word sizes (see Note #1) : */ +#ifdef _LP64 +#define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_64 /* Defines CPU address word size (in octets). */ +#define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_64 /* Defines CPU data word size (in octets). */ +#else +#define CPU_CFG_ADDR_SIZE CPU_WORD_SIZE_32 /* Defines CPU address word size (in octets). */ +#define CPU_CFG_DATA_SIZE CPU_WORD_SIZE_32 /* Defines CPU data word size (in octets). */ +#endif + + +#define CPU_CFG_DATA_SIZE_MAX CPU_WORD_SIZE_64 /* Defines CPU maximum word size (in octets). */ + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_LITTLE /* Defines CPU data word-memory order (see Note #2). */ +#else +#define CPU_CFG_ENDIAN_TYPE CPU_ENDIAN_TYPE_BIG /* Defines CPU data word-memory order (see Note #2). */ +#endif + + +/* +********************************************************************************************************* +* CONFIGURE CPU ADDRESS & DATA TYPES +********************************************************************************************************* +*/ + + /* CPU address type based on address bus size. */ +#if (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_64) +typedef CPU_INT64U CPU_ADDR; +#elif (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_ADDR; +#elif (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_ADDR; +#else +typedef CPU_INT08U CPU_ADDR; +#endif + + /* CPU data type based on data bus size. */ +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) +typedef CPU_INT64U CPU_DATA; +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) +typedef CPU_INT32U CPU_DATA; +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_DATA; +#else +typedef CPU_INT08U CPU_DATA; +#endif + + +typedef CPU_DATA CPU_ALIGN; /* Defines CPU data-word-alignment size. */ +typedef size_t CPU_SIZE_T; /* Defines CPU standard 'size_t' size. */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +* +* (2) Configure CPU_CFG_STK_ALIGN_BYTES with the highest minimum alignement required for +* cpu stacks. +********************************************************************************************************* +*/ + +#define CPU_CFG_STK_GROWTH CPU_STK_GROWTH_HI_TO_LO /* Defines CPU stack growth order (see Note #1). */ + +#define CPU_CFG_STK_ALIGN_BYTES (sizeof(CPU_ALIGN)) /* Defines CPU stack alignment in bytes. (see Note #2). */ + +typedef CPU_INT32U CPU_STK; /* Defines CPU stack data type. */ +typedef CPU_ADDR CPU_STK_SIZE; /* Defines CPU stack size data type. */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable SHOULD be declared via the CPU_SR_ALLOC() macro which, if +* used, MUST be declared following ALL other local variables. +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + /* Configure CPU critical method (see Note #1) : */ +#define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_INT_DIS_EN + +typedef CPU_BOOLEAN CPU_SR; /* Defines CPU status register size (see Note #3b). */ + + /* Allocates CPU status register word (see Note #3a). */ +#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) +#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 +#else +#define CPU_SR_ALLOC() +#endif + + + +#define CPU_INT_DIS() do { CPU_IntDis(); } while (0) /* Disable interrupts. */ +#define CPU_INT_EN() do { CPU_IntEn(); } while (0) /* Enable interrupts. */ + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + /* Disable interrupts, ... */ + /* & start interrupts disabled time measurement.*/ +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \ + CPU_IntDisMeasStart(); } while (0) + /* Stop & measure interrupts disabled time, */ + /* ... & re-enable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \ + CPU_INT_EN(); } while (0) + +#else + +#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) /* Disable interrupts. */ +#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0) /* Re-enable interrupts. */ + +#endif + +/* +********************************************************************************************************* +* MEMORY BARRIERS CONFIGURATION +* +* Note(s) : (1) (a) Configure memory barriers if required by the architecture. +* +* CPU_MB Full memory barrier. +* CPU_RMB Read (Loads) memory barrier. +* CPU_WMB Write (Stores) memory barrier. +* +********************************************************************************************************* +*/ + +#define CPU_MB() +#define CPU_RMB() +#define CPU_WMB() + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void CPU_IntInit (void); +void CPU_IntEnd (void); + +void CPU_IntDis (void); +void CPU_IntEn (void); + +void CPU_ISR_End (void); + +void CPU_TmrInterruptCreate (CPU_TMR_INTERRUPT *p_tmr_interrupt); + +void CPU_InterruptTrigger (CPU_INTERRUPT *p_interrupt); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_ADDR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_ADDR_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" + +#elif ((CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_08) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_16) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_32) && \ + (CPU_CFG_DATA_SIZE_MAX != CPU_WORD_SIZE_64)) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit alignment]" +#error " [ || CPU_WORD_SIZE_16 16-bit alignment]" +#error " [ || CPU_WORD_SIZE_32 32-bit alignment]" +#error " [ || CPU_WORD_SIZE_64 64-bit alignment]" +#endif + + + +#if (CPU_CFG_DATA_SIZE_MAX < CPU_CFG_DATA_SIZE) +#error "CPU_CFG_DATA_SIZE_MAX illegally #define'd in 'cpu.h' " +#error " [MUST be >= CPU_CFG_DATA_SIZE]" +#endif + + + + +#ifndef CPU_CFG_ENDIAN_TYPE +#error "CPU_CFG_ENDIAN_TYPE not #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" + +#elif ((CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_BIG ) && \ + (CPU_CFG_ENDIAN_TYPE != CPU_ENDIAN_TYPE_LITTLE)) +#error "CPU_CFG_ENDIAN_TYPE illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_ENDIAN_TYPE_BIG ]" +#error " [ || CPU_ENDIAN_TYPE_LITTLE]" +#endif + + + + +#ifndef CPU_CFG_STK_GROWTH +#error "CPU_CFG_STK_GROWTH not #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" + +#elif ((CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_LO_TO_HI) && \ + (CPU_CFG_STK_GROWTH != CPU_STK_GROWTH_HI_TO_LO)) +#error "CPU_CFG_STK_GROWTH illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_STK_GROWTH_LO_TO_HI]" +#error " [ || CPU_STK_GROWTH_HI_TO_LO]" +#endif + + + + +#ifndef CPU_CFG_CRITICAL_METHOD +#error "CPU_CFG_CRITICAL_METHOD not #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" + +#elif ((CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_INT_DIS_EN ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_STK ) && \ + (CPU_CFG_CRITICAL_METHOD != CPU_CRITICAL_METHOD_STATUS_LOCAL)) +#error "CPU_CFG_CRITICAL_METHOD illegally #define'd in 'cpu.h' " +#error " [MUST be CPU_CRITICAL_METHOD_INT_DIS_EN ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_STK ]" +#error " [ || CPU_CRITICAL_METHOD_STATUS_LOCAL]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu.h MODULE'. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* End of CPU module include. */ + diff --git a/rtos/uC-CPU/Posix/cpu_c.c b/rtos/uC-CPU/Posix/cpu_c.c new file mode 100644 index 00000000..73dd77d8 --- /dev/null +++ b/rtos/uC-CPU/Posix/cpu_c.c @@ -0,0 +1,885 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU PORT FILE +* +* POSIX +* +* Filename : cpu_c.c +* Version : v1.32.00 +********************************************************************************************************* +* Notes : (1) Requires a Single UNIX Specification, Version 3 compliant operating environment. +* On Linux _XOPEN_SOURCE must be defined to at least 600, generally by passing the +* -D_XOPEN_SOURCE=600 command line option to GCC. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + +#define CPU_TMR_INT_TASK_PRIO sched_get_priority_max(SCHED_RR) /* Tmr interrupt task priority. */ +#define CPU_IRQ_SIG (SIGURG) /* IRQ trigger signal. */ + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + +typedef struct cpu_interrupt_node CPU_INTERRUPT_NODE; + +struct cpu_interrupt_node { + CPU_INTERRUPT *InterruptPtr; + CPU_INTERRUPT_NODE *NextPtr; +}; + + +/* +********************************************************************************************************* +* LOCAL VARIABLES +********************************************************************************************************* +*/ + +static pthread_mutex_t CPU_InterruptQueueMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutexattr_t CPU_InterruptQueueMutexAttr; + +static CPU_INTERRUPT_NODE *CPU_InterruptPendListHeadPtr; +static CPU_INTERRUPT_NODE *CPU_InterruptRunningListHeadPtr; + +static sigset_t CPU_IRQ_SigMask; + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +#if (_POSIX_C_SOURCE < 199309L) +#error "_POSIX_C_SOURCE is required to be at least 199309L" +#endif + +static void CPU_IRQ_Handler (int sig); + +static void CPU_InterruptTriggerInternal (CPU_INTERRUPT *p_interrupt); + +static void CPU_InterruptQueue (CPU_INTERRUPT *p_isr); + +static void *CPU_TmrInterruptTask (void *p_arg); + +static void CPU_ISR_Sched (void); + + +/* +********************************************************************************************************* +* CPU_IntInit() +* +* Description : This function initializes the critical section. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : 1) CPU_IntInit() MUST be called prior to use any of the CPU_IntEn(), and CPU_IntDis() +* functions. +********************************************************************************************************* +*/ + +void CPU_IntInit (void) +{ + struct sigaction on_isr_trigger_sig_action; + int res; + + + CPU_InterruptPendListHeadPtr = DEF_NULL; + CPU_InterruptRunningListHeadPtr = DEF_NULL; + + sigemptyset(&CPU_IRQ_SigMask); + sigaddset(&CPU_IRQ_SigMask, CPU_IRQ_SIG);; + + pthread_mutexattr_init(&CPU_InterruptQueueMutexAttr); + pthread_mutexattr_settype(&CPU_InterruptQueueMutexAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&CPU_InterruptQueueMutex, &CPU_InterruptQueueMutexAttr); + + /* Register interrupt trigger signal handler. */ + memset(&on_isr_trigger_sig_action, 0, sizeof(on_isr_trigger_sig_action)); + res = sigemptyset(&on_isr_trigger_sig_action.sa_mask); + if (res != 0u) { + raise(SIGABRT); + } + on_isr_trigger_sig_action.sa_flags = SA_NODEFER; + on_isr_trigger_sig_action.sa_handler = CPU_IRQ_Handler; + res = sigaction(CPU_IRQ_SIG, &on_isr_trigger_sig_action, NULL); + if (res != 0u) { + raise(SIGABRT); + } +} + + +/* +********************************************************************************************************* +* CPU_IntDis() +* +* Description : This function disables interrupts for critical sections of code. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_IntDis (void) +{ + pthread_sigmask(SIG_BLOCK, &CPU_IRQ_SigMask, DEF_NULL); +} + + +/* +********************************************************************************************************* +* CPU_IntEn() +* +* Description : This function enables interrupts after critical sections of code. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void CPU_IntEn (void) +{ + pthread_sigmask(SIG_UNBLOCK, &CPU_IRQ_SigMask, DEF_NULL); +} + + +/* +********************************************************************************************************* +* CPU_ISR_End() +* +* Description : Ends an ISR. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) This function MUST be called at the end of an ISR. +* +********************************************************************************************************* +*/ + +void CPU_ISR_End (void) +{ + CPU_INTERRUPT_NODE *p_interrupt_node; + + + CPU_INT_DIS(); + pthread_mutex_lock(&CPU_InterruptQueueMutex); + if (CPU_InterruptRunningListHeadPtr == DEF_NULL) { + raise(SIGABRT); + } + p_interrupt_node = CPU_InterruptRunningListHeadPtr; + CPU_InterruptRunningListHeadPtr = CPU_InterruptRunningListHeadPtr->NextPtr; + pthread_mutex_unlock(&CPU_InterruptQueueMutex); + CPU_INT_EN(); + + free(p_interrupt_node); + + CPU_ISR_Sched(); +} + + +/* +********************************************************************************************************* +* CPU_TmrInterruptCreate() +* +* Description : Simulated hardware timer instance creation. +* +* Argument(s) : p_tmr_interrupt Pointer to a timer interrupt descriptor. +* +* Return(s) : none. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +void CPU_TmrInterruptCreate (CPU_TMR_INTERRUPT *p_tmr_interrupt) +{ + pthread_t thread; + pthread_attr_t attr; + struct sched_param param; + int res; + + + res = pthread_attr_init(&attr); + if (res != 0u) { + raise(SIGABRT); + } + res = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + if (res != 0u) { + raise(SIGABRT); + } + param.__sched_priority = CPU_TMR_INT_TASK_PRIO; + pthread_attr_setschedpolicy(&attr, SCHED_RR); + if (res != 0u) { + raise(SIGABRT); + } + pthread_attr_setschedparam(&attr, ¶m); + if (res != 0u) { + raise(SIGABRT); + } + + pthread_create(&thread, &attr, CPU_TmrInterruptTask, p_tmr_interrupt); +} + + +/* +********************************************************************************************************* +* CPU_InterruptTrigger() +* +* Description : Queue an interrupt and send the IRQ signal. +* +* Argument(s) : p_interrupt Interrupt to be queued. +* +* Return(s) : none. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +void CPU_InterruptTrigger (CPU_INTERRUPT *p_interrupt) +{ + CPU_INT_DIS(); + CPU_InterruptTriggerInternal(p_interrupt); /* Signal are now blocked: rest of Trigger is internal. */ + CPU_INT_EN(); +} + + +/* +********************************************************************************************************* +* CPU_Printf() +* +* Description: This function is analog of printf. +* +* Arguments : p_str Pointer to format string output. +* +* Returns : Number of characters written. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_MSG_TRACE_EN +static int CPU_Printf (char *p_str, ...) +{ + +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val', if NO error(s). +* +* 0, otherwise. +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 11 +* 0 0 0 0 1 x x x 12 +* 0 0 0 0 0 1 x x 13 +* 0 0 0 0 0 0 1 x 14 +* 0 0 0 0 0 0 0 1 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (3) For 32-bit values : +* +* b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 27 +* 0 0 0 0 1 x x x 28 +* 0 0 0 0 0 1 x x 29 +* 0 0 0 0 0 0 1 x 30 +* 0 0 0 0 0 0 0 1 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +* +* (2) MUST be implemented in cpu_a.asm if and only if CPU_CFG_LEAD_ZEROS_ASM_PRESENT +* is #define'd in 'cpu_cfg.h' or 'cpu.h'. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntLeadZeros (CPU_DATA val) +{ + +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* (4) 64-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* x x x x 1 0 0 0 3 +* x x x 1 0 0 0 0 4 +* x x 1 0 0 0 0 0 5 +* x 1 0 0 0 0 0 0 6 +* 1 0 0 0 0 0 0 0 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 11 +* x x x 1 0 0 0 0 12 +* x x 1 0 0 0 0 0 13 +* x 1 0 0 0 0 0 0 14 +* 1 0 0 0 0 0 0 0 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (3) For 32-bit values : +* +* b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 27 +* x x x 1 0 0 0 0 28 +* x x 1 0 0 0 0 0 29 +* x 1 0 0 0 0 0 0 30 +* 1 0 0 0 0 0 0 0 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (4) For 64-bit values : +* +* b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 59 +* x x x 1 0 0 0 0 60 +* x x 1 0 0 0 0 0 61 +* x 1 0 0 0 0 0 0 62 +* 1 0 0 0 0 0 0 0 63 +* 0 0 0 0 0 0 0 0 64 +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) CPU_CntTrailZeros()'s final conditional statement calculates 'val's number of +* trailing zeros based on its return data size, 'CPU_CFG_DATA_SIZE', & 'val's +* calculated number of lead zeros ONLY if the initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final statement. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntTrailZeros (CPU_DATA val) +{ + +} +#endif + +/* +********************************************************************************************************* +* CPU_TS_TmrInit() +* +* Description : Initialize & start CPU timestamp timer. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (c) When applicable, timer period SHOULD be less than the typical measured time +* but MUST be less than the maximum measured time; otherwise, timer resolution +* inadequate to measure desired times. +* +* See also 'CPU_TS_TmrRd() Note #2'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +void CPU_TS_TmrInit (void) +{ + struct timespec res; + + + res.tv_sec = 0; + res.tv_nsec = 0; + + (void)clock_settime(CLOCK_MONOTONIC, &res); + + CPU_TS_TmrFreqSet(1000000000); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrRd() +* +* Description : Get current CPU timestamp timer count value. +* +* Argument(s) : none. +* +* Return(s) : Timestamp timer count (see Notes #2a & #2b). +* +* Note(s) : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (1) If timer is a 'down' counter whose values decrease with each time count, +* then the returned timer value MUST be ones-complemented. +* +* (c) (1) When applicable, the amount of time measured by CPU timestamps is +* calculated by either of the following equations : +* +* (A) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (B) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* (2) Timer period SHOULD be less than the typical measured time but MUST be less +* than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_TS_TMR CPU_TS_TmrRd (void) +{ + struct timespec res; + CPU_TS_TMR ts; + + + (void)clock_gettime(CLOCK_MONOTONIC, &res); + + ts = (CPU_TS_TMR)(res.tv_sec * 1000000000u + res.tv_nsec); + + return (ts); +} +#endif + + +#ifdef __cplusplus +} +#endif + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_IRQ_Handler() +* +* Description : CPU_IRQ_SIG signal handler. +* +* Argument(s) : sig Signal that triggered the handler (unused). +* +* Return(s) : none. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +static void CPU_IRQ_Handler (int sig) +{ + (void)&sig; + CPU_ISR_Sched(); +} + + +/* +********************************************************************************************************* +* CPU_InterruptTriggerInternal() +* +* Description : Queue an interrupt and send the IRQ signal. +* +* Argument(s) : p_interrupt Interrupt to be queued. +* +* Return(s) : none. +* +* Note(s) : (1) The Interrupt signal must be blocked before calling this function. +********************************************************************************************************* +*/ + +void CPU_InterruptTriggerInternal (CPU_INTERRUPT *p_interrupt) +{ + if (p_interrupt->En == DEF_NO) { + return; + } + + CPU_InterruptQueue(p_interrupt); + + kill(getpid(), CPU_IRQ_SIG); + + if (p_interrupt->TraceEn == DEF_ENABLED) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + printf("@ %lu:%06lu", ts.tv_sec, ts.tv_nsec / 1000u); + printf(" %s interrupt fired.\r\n", p_interrupt->NamePtr); + } +} + + +/* +********************************************************************************************************* +* CPU_InterruptQueue() +* +* Description : Queue an interrupt. +* +* Argument(s) : p_interrupt Pointer to the interrupt to be queued. +* +* Return(s) : none. +* +* Note(s) : (1) The signals for this thread are already blocked during this function call. +* +* (2) Since the signal are already blocked, it is safe to lock and release the mutex. +********************************************************************************************************* +*/ + +static void CPU_InterruptQueue (CPU_INTERRUPT *p_interrupt) +{ + CPU_INTERRUPT_NODE *p_cur_interrupt_node; + CPU_INTERRUPT_NODE *p_prev_interrupt_node; + CPU_INTERRUPT_NODE *p_interrupt_node; + + + p_interrupt_node = (CPU_INTERRUPT_NODE *)malloc(sizeof(CPU_INTERRUPT_NODE)); + p_interrupt_node->InterruptPtr = p_interrupt; + + pthread_mutex_lock(&CPU_InterruptQueueMutex); + if ((CPU_InterruptPendListHeadPtr == DEF_NULL) || + (CPU_InterruptPendListHeadPtr->InterruptPtr->Prio < p_interrupt->Prio)) { + p_interrupt_node->NextPtr = CPU_InterruptPendListHeadPtr; + CPU_InterruptPendListHeadPtr = p_interrupt_node; + } else { + p_cur_interrupt_node = CPU_InterruptPendListHeadPtr; + while ((p_cur_interrupt_node != DEF_NULL) && + (p_cur_interrupt_node->InterruptPtr->Prio >= p_interrupt->Prio)) { + p_prev_interrupt_node = p_cur_interrupt_node; + p_cur_interrupt_node = p_cur_interrupt_node->NextPtr; + } + p_prev_interrupt_node->NextPtr = p_interrupt_node; + p_interrupt_node->NextPtr = p_cur_interrupt_node; + } + pthread_mutex_unlock(&CPU_InterruptQueueMutex); +} + + +/* +********************************************************************************************************* +* CPU_ISR_Sched() +* +* Description : Schedules the highest priority pending interrupt. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +static void CPU_ISR_Sched (void) +{ + CPU_INTERRUPT_NODE *p_isr_node; + + + CPU_INT_DIS(); + pthread_mutex_lock(&CPU_InterruptQueueMutex); + p_isr_node = CPU_InterruptPendListHeadPtr; + if ((p_isr_node != DEF_NULL) && + ((CPU_InterruptRunningListHeadPtr == DEF_NULL) || + (p_isr_node->InterruptPtr->Prio > CPU_InterruptRunningListHeadPtr->InterruptPtr->Prio))) { + CPU_InterruptPendListHeadPtr = CPU_InterruptPendListHeadPtr->NextPtr; + p_isr_node->NextPtr = CPU_InterruptRunningListHeadPtr; + CPU_InterruptRunningListHeadPtr = p_isr_node; + pthread_mutex_unlock(&CPU_InterruptQueueMutex); + CPU_INT_EN(); + p_isr_node->InterruptPtr->ISR_Fnct(); + } else { + pthread_mutex_unlock(&CPU_InterruptQueueMutex); + CPU_INT_EN(); + } +} + + +/* +********************************************************************************************************* +* CPU_TmrInterruptTask() +* +* Description : Hardware timer interrupt simulation function. +* +* Argument(s) : p_arg Pointer to a timer interrupt descriptor. +* +* Return(s) : none. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +static void *CPU_TmrInterruptTask (void *p_arg) { + + struct timespec tspec, tspec_rem; + int res; + CPU_TMR_INTERRUPT *p_tmr_int; + CPU_BOOLEAN one_shot; + + CPU_INT_DIS(); + + p_tmr_int = (CPU_TMR_INTERRUPT *)p_arg; + + tspec.tv_nsec = p_tmr_int->PeriodMuSec * 1000u; + tspec.tv_sec = p_tmr_int->PeriodSec; + + one_shot = p_tmr_int->OneShot; + + do { + tspec_rem = tspec; + do {res = clock_nanosleep(CLOCK_MONOTONIC, 0u, &tspec_rem, &tspec_rem); } while (res == EINTR); + if (res != 0u) { raise(SIGABRT); } + CPU_InterruptTriggerInternal(&(p_tmr_int->Interrupt)); /* See Note #2. */ + } while (one_shot != DEF_YES); + + pthread_exit(DEF_NULL); + + return (NULL); +} diff --git a/rtos/uC-CPU/cpu_cache.h b/rtos/uC-CPU/cpu_cache.h new file mode 100644 index 00000000..e8631815 --- /dev/null +++ b/rtos/uC-CPU/cpu_cache.h @@ -0,0 +1,135 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CACHE CPU MODULE +* +* Filename : cpu_cache.h +* Version : v1.32.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This cache CPU header file is protected from multiple pre-processor inclusion through use of +* the cache CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_CACHE_MODULE_PRESENT /* See Note #1. */ +#define CPU_CACHE_MODULE_PRESENT + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef CPU_CACHE_MODULE +#define CPU_CACHE_EXT +#else +#define CPU_CACHE_EXT extern +#endif + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include +#include +#include + + +/* +********************************************************************************************************* +* CACHE CONFIGURATION +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_CACHE_MGMT_EN +#define CPU_CFG_CACHE_MGMT_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* CACHE OPERATIONS DEFINES +********************************************************************************************************* +*/ + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) +#ifndef CPU_DCACHE_RANGE_FLUSH +#define CPU_DCACHE_RANGE_FLUSH(addr_start, len) CPU_DCache_RangeFlush(addr_start, len) +#endif /* CPU_DCACHE_RANGE_FLUSH */ +#else +#define CPU_DCACHE_RANGE_FLUSH(addr_start, len) +#endif /* CPU_CFG_CACHE_MGMT_EN) */ + + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) +#ifndef CPU_DCACHE_RANGE_INV +#define CPU_DCACHE_RANGE_INV(addr_start, len) CPU_DCache_RangeInv(addr_start, len) +#endif /* CPU_DCACHE_RANGE_INV */ +#else +#define CPU_DCACHE_RANGE_INV(addr_start, len) +#endif /* CPU_CFG_CACHE_MGMT_EN) */ + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) + +#ifdef __cplusplus +extern "C" { +#endif + +void CPU_Cache_Init (void); + +void CPU_DCache_RangeFlush(void *addr_start, + CPU_ADDR len); + +void CPU_DCache_RangeInv (void *addr_start, + CPU_ADDR len); + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_CFG_CACHE_MGMT_EN */ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu_core.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of CPU core module include. */ diff --git a/rtos/uC-CPU/cpu_core.c b/rtos/uC-CPU/cpu_core.c new file mode 100644 index 00000000..5c1f5993 --- /dev/null +++ b/rtos/uC-CPU/cpu_core.c @@ -0,0 +1,2254 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CPU MODULE +* +* Filename : cpu_core.c +* Version : v1.32.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define CPU_CORE_MODULE +#include "cpu_core.h" + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) +#include "cpu_cache.h" +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + /* Pop cnt algorithm csts. */ +#define CRC_UTIL_POPCNT_MASK01010101_32 0x55555555u +#define CRC_UTIL_POPCNT_MASK00110011_32 0x33333333u +#define CRC_UTIL_POPCNT_MASK00001111_32 0x0F0F0F0Fu +#define CRC_UTIL_POPCNT_POWERSOF256_32 0x01010101u + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU COUNT LEAD ZEROs LOOKUP TABLE +* +* Note(s) : (1) Index into bit pattern table determines the number of leading zeros in an 8-bit value : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +********************************************************************************************************* +*/ + +#if (!(defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) || \ + (CPU_CFG_DATA_SIZE_MAX > CPU_CFG_DATA_SIZE)) +static const CPU_INT08U CPU_CntLeadZerosTbl[256] = { /* Data vals : */ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 8u, 7u, 6u, 6u, 5u, 5u, 5u, 5u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, /* 0x00 to 0x0F */ + 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, /* 0x10 to 0x1F */ + 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x20 to 0x2F */ + 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, /* 0x30 to 0x3F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x40 to 0x4F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x50 to 0x5F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x60 to 0x6F */ + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, /* 0x70 to 0x7F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x80 to 0x8F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0x90 to 0x9F */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xA0 to 0xAF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xB0 to 0xBF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xC0 to 0xCF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xD0 to 0xDF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, /* 0xE0 to 0xEF */ + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u /* 0xF0 to 0xFF */ +}; +#endif + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + +CPU_INT32U const CPU_EndiannessTest = 0x12345678LU; /* Variable to test CPU endianness. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) /* ---------------- CPU NAME FNCTS ---------------- */ +static void CPU_NameInit (void); +#endif + + + /* ----------------- CPU TS FNCTS ----------------- */ +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) +static void CPU_TS_Init (void); +#endif + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN /* ---------- CPU INT DIS TIME MEAS FNCTS --------- */ +static void CPU_IntDisMeasInit (void); + +static CPU_TS_TMR CPU_IntDisMeasMaxCalc(CPU_TS_TMR time_tot_cnts); +#endif + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU_Init() +* +* Description : (1) Initialize CPU module : +* +* (a) Initialize CPU timestamps +* (b) Initialize CPU interrupts disabled time measurements +* (c) Initialize CPU host name +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (2) CPU_Init() MUST be called ... : +* +* (a) ONLY ONCE from a product's application; ... +* (b) BEFORE product's application calls any core CPU module function(s) +* +* (3) The following initialization functions MUST be sequenced as follows : +* +* (a) CPU_TS_Init() SHOULD precede ALL calls to other CPU timestamp functions +* +* (b) CPU_IntDisMeasInit() SHOULD precede ALL calls to CPU_CRITICAL_ENTER()/CPU_CRITICAL_EXIT() +* & other CPU interrupts disabled time measurement functions +********************************************************************************************************* +*/ + +void CPU_Init (void) +{ + /* --------------------- INIT TS ---------------------- */ +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) + CPU_TS_Init(); /* See Note #3a. */ +#endif + /* -------------- INIT INT DIS TIME MEAS -------------- */ +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_IntDisMeasInit(); /* See Note #3b. */ +#endif + + /* ------------------ INIT CPU NAME ------------------- */ +#if (CPU_CFG_NAME_EN == DEF_ENABLED) + CPU_NameInit(); +#endif + +#if (CPU_CFG_CACHE_MGMT_EN == DEF_ENABLED) + CPU_Cache_Init(); +#endif +} + + +/* +********************************************************************************************************* +* CPU_SW_Exception() +* +* Description : Trap unrecoverable software exception. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) CPU_SW_Exception() deadlocks the current code execution -- whether multi-tasked/ +* -processed/-threaded or single-threaded -- when the current code execution cannot +* gracefully recover or report a fault or exception condition. +* +* See also 'cpu_core.h CPU_SW_EXCEPTION() Note #1'. +********************************************************************************************************* +*/ + +void CPU_SW_Exception (void) +{ + for (;;) { + ; + } +} + + +/* +********************************************************************************************************* +* CPU_NameClr() +* +* Description : Clear CPU Name. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameClr (void) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + Mem_Clr((void *)&CPU_Name[0], + (CPU_SIZE_T) CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_NameGet() +* +* Description : Get CPU host name. +* +* Argument(s) : p_name Pointer to an ASCII character array that will receive the return CPU host +* name ASCII string from this function (see Note #1). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU host name successfully returned. +* CPU_ERR_NULL_PTR Argument 'p_name' passed a NULL pointer. +* +* Return(s) : none. +* +* Note(s) : (1) The size of the ASCII character array that will receive the return CPU host name +* ASCII string : +* +* (a) MUST be greater than or equal to the current CPU host name's ASCII string +* size including the terminating NULL character; +* (b) SHOULD be greater than or equal to CPU_CFG_NAME_SIZE +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameGet (CPU_CHAR *p_name, + CPU_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(;); + } + + if (p_name == (CPU_CHAR *)0) { + *p_err = CPU_ERR_NULL_PTR; + return; + } + + CPU_CRITICAL_ENTER(); + (void)Str_Copy_N(p_name, + &CPU_Name[0], + CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); + + *p_err = CPU_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* CPU_NameSet() +* +* Description : Set CPU host name. +* +* Argument(s) : p_name Pointer to CPU host name to set. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU host name successfully set. +* CPU_ERR_NULL_PTR Argument 'p_name' passed a NULL pointer. +* CPU_ERR_NAME_SIZE Invalid CPU host name size (see Note #1). +* +* Return(s) : none. +* +* Note(s) : (1) 'p_name' ASCII string size, including the terminating NULL character, MUST be less +* than or equal to CPU_CFG_NAME_SIZE. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +void CPU_NameSet (const CPU_CHAR *p_name, + CPU_ERR *p_err) +{ + CPU_SIZE_T len; + CPU_SR_ALLOC(); + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(;); + } + + if (p_name == (const CPU_CHAR *)0) { + *p_err = CPU_ERR_NULL_PTR; + return; + } + + len = Str_Len_N(p_name, + CPU_CFG_NAME_SIZE); + if (len < CPU_CFG_NAME_SIZE) { /* If cfg name len < max name size, ... */ + CPU_CRITICAL_ENTER(); + (void)Str_Copy_N(&CPU_Name[0], /* ... copy cfg name to CPU host name. */ + p_name, + CPU_CFG_NAME_SIZE); + CPU_CRITICAL_EXIT(); + *p_err = CPU_ERR_NONE; + + } else { + *p_err = CPU_ERR_NAME_SIZE; + } +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Get32() +* +* Description : Get current 32-bit CPU timestamp. +* +* Argument(s) : none. +* +* Return(s) : Current 32-bit CPU timestamp (in timestamp timer counts). +* +* Note(s) : (1) When applicable, the amount of time measured by CPU timestamps is calculated by +* either of the following equations : +* +* (a) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (b) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c1'. +* +* (2) In case the CPU timestamp timer has lower precision than the 32-bit CPU timestamp; +* its precision is extended via periodic updates by accumulating the deltas of the +* timestamp timer count values into the higher-precision 32-bit CPU timestamp. +* +* (3) After initialization, 'CPU_TS_32_Accum' & 'CPU_TS_32_TmrPrev' MUST ALWAYS +* be accessed AND updated exclusively with interrupts disabled -- but NOT +* with critical sections. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_TS32 CPU_TS_Get32 (void) +{ + CPU_TS32 ts; +#if (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32) + CPU_TS_TMR tmr_cur; + CPU_TS_TMR tmr_delta; + CPU_SR_ALLOC(); + +#endif + +#if (CPU_CFG_TS_TMR_SIZE >= CPU_WORD_SIZE_32) + ts = (CPU_TS32)CPU_TS_TmrRd(); /* Get cur ts tmr val (in 32-bit ts cnts). */ + +#else + CPU_INT_DIS(); + tmr_cur = (CPU_TS_TMR) CPU_TS_TmrRd(); /* Get cur ts tmr val (in ts tmr cnts). */ + tmr_delta = (CPU_TS_TMR)(tmr_cur - CPU_TS_32_TmrPrev); /* Calc delta ts tmr cnts. */ + CPU_TS_32_Accum += (CPU_TS32 ) tmr_delta; /* Inc ts by delta ts tmr cnts (see Note #2). */ + CPU_TS_32_TmrPrev = (CPU_TS_TMR) tmr_cur; /* Save cur ts tmr cnts for next update. */ + ts = (CPU_TS32 ) CPU_TS_32_Accum; + CPU_INT_EN(); +#endif + + return (ts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Get64() +* +* Description : Get current 64-bit CPU timestamp. +* +* Argument(s) : none. +* +* Return(s) : Current 64-bit CPU timestamp (in timestamp timer counts). +* +* Note(s) : (1) When applicable, the amount of time measured by CPU timestamps is calculated by +* either of the following equations : +* +* (a) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (b) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c1'. +* +* (2) In case the CPU timestamp timer has lower precision than the 64-bit CPU timestamp; +* its precision is extended via periodic updates by accumulating the deltas of the +* timestamp timer count values into the higher-precision 64-bit CPU timestamp. +* +* (3) After initialization, 'CPU_TS_64_Accum' & 'CPU_TS_64_TmrPrev' MUST ALWAYS +* be accessed AND updated exclusively with interrupts disabled -- but NOT +* with critical sections. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_TS64 CPU_TS_Get64 (void) +{ + CPU_TS64 ts; +#if (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64) + CPU_TS_TMR tmr_cur; + CPU_TS_TMR tmr_delta; + CPU_SR_ALLOC(); +#endif + + +#if (CPU_CFG_TS_TMR_SIZE >= CPU_WORD_SIZE_64) + ts = (CPU_TS64)CPU_TS_TmrRd(); /* Get cur ts tmr val (in 64-bit ts cnts). */ + +#else + CPU_INT_DIS(); + tmr_cur = (CPU_TS_TMR) CPU_TS_TmrRd(); /* Get cur ts tmr val (in ts tmr cnts). */ + tmr_delta = (CPU_TS_TMR)(tmr_cur - CPU_TS_64_TmrPrev); /* Calc delta ts tmr cnts. */ + CPU_TS_64_Accum += (CPU_TS64 ) tmr_delta; /* Inc ts by delta ts tmr cnts (see Note #2). */ + CPU_TS_64_TmrPrev = (CPU_TS_TMR) tmr_cur; /* Save cur ts tmr cnts for next update. */ + ts = (CPU_TS64 ) CPU_TS_64_Accum; + CPU_INT_EN(); +#endif + + return (ts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Update() +* +* Description : Update current CPU timestamp(s). +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) (a) CPU timestamp(s) MUST be updated periodically by some application (or BSP) time +* handler in order to (adequately) maintain CPU timestamp(s)' time. +* +* (b) CPU timestamp(s) MUST be updated more frequently than the CPU timestamp timer +* overflows; otherwise, CPU timestamp(s) will lose time. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c2'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_EN == DEF_ENABLED) +void CPU_TS_Update (void) +{ +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) + (void)CPU_TS_Get32(); +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) + (void)CPU_TS_Get64(); +#endif +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrFreqGet() +* +* Description : Get CPU timestamp's timer frequency. +* +* Argument(s) : p_err Pointer to variable that will receive the return error code from this function : +* +* CPU_ERR_NONE CPU timestamp's timer frequency successfully +* returned. +* CPU_ERR_TS_FREQ_INVALID CPU timestamp's timer frequency invalid &/or +* NOT yet configured. +* +* Return(s) : CPU timestamp's timer frequency (in Hertz), if NO error(s). +* +* 0, otherwise. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_TS_TMR_FREQ CPU_TS_TmrFreqGet (CPU_ERR *p_err) +{ + CPU_TS_TMR_FREQ freq_hz; + + + if (p_err == (CPU_ERR *)0) { + CPU_SW_EXCEPTION(0); + } + + freq_hz = CPU_TS_TmrFreq_Hz; + *p_err = (freq_hz != 0u) ? CPU_ERR_NONE : CPU_ERR_TS_FREQ_INVALID; + + return (freq_hz); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrFreqSet() +* +* Description : Set CPU timestamp's timer frequency. +* +* Argument(s) : freq_hz Frequency (in Hertz) to set for CPU timestamp's timer. +* +* Return(s) : none. +* +* Note(s) : (1) (a) (1) CPU timestamp timer frequency is NOT required for internal CPU timestamp +* operations but may OPTIONALLY be configured by CPU_TS_TmrInit() or other +* application/BSP initialization functions. +* +* (2) CPU timestamp timer frequency MAY be used with optional CPU_TSxx_to_uSec() +* to convert CPU timestamps from timer counts into microseconds. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2a'. +* +* (b) CPU timestamp timer period SHOULD be less than the typical measured time but MUST +* be less than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2b'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +void CPU_TS_TmrFreqSet (CPU_TS_TMR_FREQ freq_hz) +{ + CPU_TS_TmrFreq_Hz = freq_hz; +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCurReset() +* +* Description : Reset current maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : Maximum interrupts disabled time (in CPU timestamp timer counts) before resetting. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMaxCur_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxCurReset (void) +{ + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + time_max_cnts = CPU_IntDisMeasMaxCurGet(); + CPU_INT_DIS(); + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_INT_EN(); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCurGet() +* +* Description : Get current maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : Current maximum interrupts disabled time (in CPU timestamp timer counts). +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMaxCur_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxCurGet (void) +{ + CPU_TS_TMR time_tot_cnts; + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + CPU_INT_DIS(); + time_tot_cnts = CPU_IntDisMeasMaxCur_cnts; + CPU_INT_EN(); + time_max_cnts = CPU_IntDisMeasMaxCalc(time_tot_cnts); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxGet() +* +* Description : Get (non-resetable) maximum interrupts disabled time. +* +* Argument(s) : none. +* +* Return(s) : (Non-resetable) maximum interrupts disabled time (in CPU timestamp timer counts). +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* Note(s) : (1) After initialization, 'CPU_IntDisMeasMax_cnts' MUST ALWAYS be accessed +* exclusively with interrupts disabled -- but NOT with critical sections. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_TS_TMR CPU_IntDisMeasMaxGet (void) +{ + CPU_TS_TMR time_tot_cnts; + CPU_TS_TMR time_max_cnts; + CPU_SR_ALLOC(); + + + CPU_INT_DIS(); + time_tot_cnts = CPU_IntDisMeasMax_cnts; + CPU_INT_EN(); + time_max_cnts = CPU_IntDisMeasMaxCalc(time_tot_cnts); + + return (time_max_cnts); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasStart() +* +* Description : Start interrupts disabled time measurement. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +void CPU_IntDisMeasStart (void) +{ + CPU_IntDisMeasCtr++; + if (CPU_IntDisNestCtr == 0u) { /* If ints NOT yet dis'd, ... */ + CPU_IntDisMeasStart_cnts = CPU_TS_TmrRd(); /* ... get ints dis'd start time. */ + } + CPU_IntDisNestCtr++; +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasStop() +* +* Description : Stop interrupts disabled time measurement. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) (a) The total amount of time interrupts are disabled by system &/or application code +* during critical sections is calculated by the following equations : +* +* (1) When interrupts disabled time measurements are disabled : +* +* +* | CRITICAL | | CRITICAL | +* |<- SECTION ->| |<- SECTION ->| +* | ENTER | | EXIT | +* +* Disable Enable +* Interrupts Interrupts +* +* || || || || +* || || || || +* || | ||<------------------------->|| | || +* || |<->|| | ||<----->| || +* || | | || | || | | || +* | | | | | +* interrupts time interrupts +* disabled interrupts |enabled +* | disabled | +* | (via application) | +* time time +* interrupts interrupts +* disabled ovrhd enabled ovrhd +* +* +* (A) time = [ time - time ] - time +* interrupts [ interrupts interrupts ] total +* disabled [ enabled disabled ] ovrhd +* (via application) +* +* +* (B) time = time + time +* total interrupts interrupts +* ovrhd enabled ovrhd disabled ovrhd +* +* +* where +* +* time time interrupts are disabled between +* interrupts first critical section enter & +* disabled last critical section exit (i.e. +* (via application) minus total overhead time) +* +* time time when interrupts are disabled +* interrupts +* disabled +* +* time time when interrupts are enabled +* interrupts +* enabled +* +* +* time total overhead time to disable/enable +* total interrupts during critical section +* ovrhd enter & exit +* +* time total overhead time to disable interrupts +* interrupts during critical section enter +* disabled ovrhd +* +* time total overhead time to enable interrupts +* interrupts during critical section exit +* enabled ovrhd +* +* +* (2) When interrupts disabled time measurements are enabled : +* +* +* | | | | +* |<----- CRITICAL SECTION ENTER ----->| |<------- CRITICAL SECTION EXIT ------->| +* | | | | +* +* Time Time +* Disable Measurement Measurement Enable +* Interrupts Start Stop Interrupts +* +* || | || || | || +* || | || || | || +* || | | ||<------------------------->|| | | || +* || | | |<----------->|| | ||<------------->| | | || +* || | | | | || | || | | | | || +* | | | | | | | +* interrupts get | time | get interrupts +* disabled start time | interrupts | stop time enabled +* meas | disabled | meas +* time (via application) time +* start meas stop meas +* ovrhd ovrhd +* +* +* (A) time = [ time - time ] - time +* interrupts [ stop start ] total meas +* disabled [ meas meas ] ovrhd +* (via application) +* +* +* (B) time = time + time +* total meas start meas stop meas +* ovrhd ovrhd ovrhd +* +* +* where +* +* time time interrupts are disabled between first +* interrupts critical section enter & last critical +* disabled section exit (i.e. minus measurement +* (via application) overhead time; however, this does NOT +* include any overhead time to disable +* or enable interrupts during critical +* section enter & exit) +* +* time time of disable interrupts start time +* start measurement (in timer counts) +* meas +* +* time time of disable interrupts stop time +* stop measurement (in timer counts) +* meas +* +* +* time total overhead time to start/stop disabled +* total meas interrupts time measurements (in timer +* ovrhd counts) +* +* time total overhead time after getting start +* start meas time until end of start measurement +* ovrhd function (in timer counts) +* +* time total overhead time from beginning of stop +* stop meas measurement function until after getting +* ovrhd stop time (in timer counts) +* +* +* (b) (1) (A) In order to correctly handle unsigned subtraction overflows of start times +* from stop times, CPU timestamp timer count values MUST be returned via +* word-size-configurable 'CPU_TS_TMR' data type. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2a'. +* +* (B) Since unsigned subtraction of start times from stop times assumes increasing +* values, timestamp timer count values MUST increase with each time count. +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2b'. +* +* (2) (A) To expedite & reduce interrupts disabled time measurement overhead; only the +* subtraction of start times from stop times is performed. +* +* (B) The final calculations to subtract the interrupts disabled time measurement +* overhead is performed asynchronously in appropriate API functions. +* +* See also 'CPU_IntDisMeasMaxCalc() Note #1b'. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +void CPU_IntDisMeasStop (void) +{ + CPU_TS_TMR time_ints_disd_cnts; + + + CPU_IntDisNestCtr--; + if (CPU_IntDisNestCtr == 0u) { /* If ints NO longer dis'd, ... */ + CPU_IntDisMeasStop_cnts = CPU_TS_TmrRd(); /* ... get ints dis'd stop time & ... */ + /* ... calc ints dis'd tot time (see Note #1b2A). */ + time_ints_disd_cnts = CPU_IntDisMeasStop_cnts - + CPU_IntDisMeasStart_cnts; + /* Calc max ints dis'd times. */ + if (CPU_IntDisMeasMaxCur_cnts < time_ints_disd_cnts) { + CPU_IntDisMeasMaxCur_cnts = time_ints_disd_cnts; + } + if (CPU_IntDisMeasMax_cnts < time_ints_disd_cnts) { + CPU_IntDisMeasMax_cnts = time_ints_disd_cnts; + } + } +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val', if NO error(s). +* +* DEF_INT_CPU_U_MAX_VAL, otherwise. +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* (4) 64-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 11 +* 0 0 0 0 1 x x x 12 +* 0 0 0 0 0 1 x x 13 +* 0 0 0 0 0 0 1 x 14 +* 0 0 0 0 0 0 0 1 15 +* 0 0 0 0 0 0 0 0 16 +* +* (3) For 32-bit values : +* +* b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 27 +* 0 0 0 0 1 x x x 28 +* 0 0 0 0 0 1 x x 29 +* 0 0 0 0 0 0 1 x 30 +* 0 0 0 0 0 0 0 1 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (4) For 64-bit values : +* +* b63 b62 b61 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 59 +* 0 0 0 0 1 x x x 60 +* 0 0 0 0 0 1 x x 61 +* 0 0 0 0 0 0 1 x 62 +* 0 0 0 0 0 0 0 1 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntLeadZeros (CPU_DATA val) +{ + CPU_DATA nbr_lead_zeros; + + +#if (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_08) + nbr_lead_zeros = CPU_CntLeadZeros08((CPU_INT08U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) + nbr_lead_zeros = CPU_CntLeadZeros16((CPU_INT16U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32) + nbr_lead_zeros = CPU_CntLeadZeros32((CPU_INT32U)val); + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) + nbr_lead_zeros = CPU_CntLeadZeros64((CPU_INT64U)val); + +#else /* See Note #1a. */ + nbr_lead_zeros = DEF_INT_CPU_U_MAX_VAL; +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros08() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in an 8-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Note(s) : (1) Supports 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* 0 0 0 1 x x x x 3 +* 0 0 0 0 1 x x x 4 +* 0 0 0 0 0 1 x x 5 +* 0 0 0 0 0 0 1 x 6 +* 0 0 0 0 0 0 0 1 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntLeadZeros08 (CPU_INT08U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_08) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros16() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 16-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Note(s) : (1) Supports 16-bit values : +* +* b15 b14 b13 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 11 +* 0 0 0 0 1 x x x 12 +* 0 0 0 0 0 1 x x 13 +* 0 0 0 0 0 0 1 x 14 +* 0 0 0 0 0 0 0 1 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntLeadZeros16 (CPU_INT16U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_16) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x00FFu) { /* Chk bits [15:08] : */ + val >>= 8u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 8u); /* .. plus nbr msb lead zeros = 8 bits.*/ + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros32() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 32-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Note(s) : (1) Supports 32-bit values : +* +* b31 b30 b29 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 27 +* 0 0 0 0 1 x x x 28 +* 0 0 0 0 0 1 x x 29 +* 0 0 0 0 0 0 1 x 30 +* 0 0 0 0 0 0 0 1 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntLeadZeros32 (CPU_INT32U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_32) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x0000FFFFu) { + if (val > 0x00FFFFFFu) { /* Chk bits [31:24] : */ + val >>= 24u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 24 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [23:16] : */ + val >>= 16u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 16 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 8u);/* .. plus nbr msb lead zeros = 8 bits.*/ + } + + } else { + if (val > 0x000000FFu) { /* Chk bits [15:08] : */ + val >>= 8u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 16u);/* .. plus nbr msb lead zeros = 16 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_DATA)CPU_CntLeadZerosTbl[ix] + 24u);/* .. plus nbr msb lead zeros = 24 bits.*/ + } + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntLeadZeros64() +* +* Description : Count the number of contiguous, most-significant, leading zero bits in a 64-bit data value. +* +* Argument(s) : val Data value to count leading zero bits. +* +* Return(s) : Number of contiguous, most-significant, leading zero bits in 'val'. +* +* Note(s) : (1) Supports 64-bit values : +* +* b63 b62 b61 ... b04 b03 b02 b01 b00 # Leading Zeros +* --- --- --- --- --- --- --- --- --------------- +* 1 x x x x x x x 0 +* 0 1 x x x x x x 1 +* 0 0 1 x x x x x 2 +* : : : : : : : : : +* : : : : : : : : : +* 0 0 0 1 x x x x 59 +* 0 0 0 0 1 x x x 60 +* 0 0 0 0 0 1 x x 61 +* 0 0 0 0 0 0 1 x 62 +* 0 0 0 0 0 0 0 1 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* See also 'CPU COUNT LEAD ZEROs LOOKUP TABLE Note #1'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntLeadZeros64 (CPU_INT64U val) +{ +#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64))) + CPU_DATA ix; +#endif + CPU_DATA nbr_lead_zeros; + + /* ---------- ASM-OPTIMIZED ----------- */ +#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64)) + nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val); + nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_64) * DEF_OCTET_NBR_BITS; + + +#else /* ----------- C-OPTIMIZED ------------ */ + if (val > 0x00000000FFFFFFFFuLL) { + if (val > 0x0000FFFFFFFFFFFFuLL) { + if (val > 0x00FFFFFFFFFFFFFFuLL) { /* Chk bits [63:56] : */ + val >>= 56u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 56 bits */ + nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix]); /* .. plus nbr msb lead zeros = 0 bits.*/ + + } else { /* Chk bits [55:48] : */ + val >>= 48u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 48 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 8u);/* .. plus nbr msb lead zeros = 8 bits.*/ + } + + } else { + if (val > 0x000000FFFFFFFFFFuLL) { /* Chk bits [47:40] : */ + val >>= 40u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 40 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 16u);/* .. plus nbr msb lead zeros = 16 bits.*/ + + } else { /* Chk bits [39:32] : */ + val >>= 32u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 32 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 24u);/* .. plus nbr msb lead zeros = 24 bits.*/ + } + } + + } else { + if (val > 0x000000000000FFFFuLL) { + if (val > 0x0000000000FFFFFFuLL) { /* Chk bits [31:24] : */ + val >>= 24u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 24 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 32u);/* .. plus nbr msb lead zeros = 32 bits.*/ + + } else { /* Chk bits [23:16] : */ + val >>= 16u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 16 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 40u);/* .. plus nbr msb lead zeros = 40 bits.*/ + } + + } else { + if (val > 0x00000000000000FFuLL) { /* Chk bits [15:08] : */ + val >>= 8u; /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 8 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 48u);/* .. plus nbr msb lead zeros = 48 bits.*/ + + } else { /* Chk bits [07:00] : */ + /* .. Nbr lead zeros = .. */ + ix = (CPU_DATA)(val); /* .. lookup tbl ix = 'val' >> 0 bits */ + nbr_lead_zeros = (CPU_DATA)((CPU_INT64U)CPU_CntLeadZerosTbl[ix] + 56u);/* .. plus nbr msb lead zeros = 56 bits.*/ + } + } + } +#endif + + + return (nbr_lead_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) (a) Supports the following data value sizes : +* +* (1) 8-bits +* (2) 16-bits +* (3) 32-bits +* (4) 64-bits +* +* See also 'cpu_def.h CPU WORD CONFIGURATION Note #1'. +* +* (b) (1) For 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* x x x x 1 0 0 0 3 +* x x x 1 0 0 0 0 4 +* x x 1 0 0 0 0 0 5 +* x 1 0 0 0 0 0 0 6 +* 1 0 0 0 0 0 0 0 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For 16-bit values : +* +* b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 11 +* x x x 1 0 0 0 0 12 +* x x 1 0 0 0 0 0 13 +* x 1 0 0 0 0 0 0 14 +* 1 0 0 0 0 0 0 0 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (3) For 32-bit values : +* +* b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 27 +* x x x 1 0 0 0 0 28 +* x x 1 0 0 0 0 0 29 +* x 1 0 0 0 0 0 0 30 +* 1 0 0 0 0 0 0 0 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (4) For 64-bit values : +* +* b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 59 +* x x x 1 0 0 0 0 60 +* x x 1 0 0 0 0 0 61 +* x 1 0 0 0 0 0 0 62 +* 1 0 0 0 0 0 0 0 63 +* 0 0 0 0 0 0 0 0 64 +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) CPU_CntTrailZeros()'s final conditional statement calculates 'val's number of +* trailing zeros based on its return data size, 'CPU_CFG_DATA_SIZE', & 'val's +* calculated number of lead zeros ONLY if the initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT +CPU_DATA CPU_CntTrailZeros (CPU_DATA val) +{ + CPU_DATA val_bit_mask; + CPU_DATA nbr_lead_zeros; + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return ((CPU_DATA)(CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS)); + } + + + val_bit_mask = val & ((CPU_DATA)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_DATA)((CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros); + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros08() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in an 8-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) Supports 8-bit values : +* +* b07 b06 b05 b04 b03 b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* x x x x 1 0 0 0 3 +* x x x 1 0 0 0 0 4 +* x x 1 0 0 0 0 0 5 +* x 1 0 0 0 0 0 0 6 +* 1 0 0 0 0 0 0 0 7 +* 0 0 0 0 0 0 0 0 8 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros08()'s 8-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros08()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_08) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 8-bit +* values would return a number of trailing zeros less than or equal to 8 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 8-bit data value bits. +* +* (b) For CPU_CntTrailZeros08()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros08()'s +* 8-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntTrailZeros08 (CPU_INT08U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08))) + CPU_INT08U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return ((CPU_DATA)(CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS)); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_08)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT08U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros08(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_DATA)((CPU_WORD_SIZE_08 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros); +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros16() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 16-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) Supports 16-bit values : +* +* b15 b14 b13 b12 b11 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 11 +* x x x 1 0 0 0 0 12 +* x x 1 0 0 0 0 0 13 +* x 1 0 0 0 0 0 0 14 +* 1 0 0 0 0 0 0 0 15 +* 0 0 0 0 0 0 0 0 16 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros16()'s 16-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros16()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_16) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 16-bit +* values would return a number of trailing zeros less than or equal to 16 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 16-bit data value bits. +* +* (b) For CPU_CntTrailZeros16()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros16()'s +* 16-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntTrailZeros16 (CPU_INT16U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16))) + CPU_INT16U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return ((CPU_DATA)(CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS)); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_16)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT16U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros16(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_DATA)((CPU_WORD_SIZE_16 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros); +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros32() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 32-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) Supports 32-bit values : +* +* b31 b30 b29 b28 b27 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 27 +* x x x 1 0 0 0 0 28 +* x x 1 0 0 0 0 0 29 +* x 1 0 0 0 0 0 0 30 +* 1 0 0 0 0 0 0 0 31 +* 0 0 0 0 0 0 0 0 32 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros32()'s 32-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros32()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_32) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 32-bit +* values would return a number of trailing zeros less than or equal to 32 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 32-bit data value bits. +* +* (b) For CPU_CntTrailZeros32()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros32()'s +* 32-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntTrailZeros32 (CPU_INT32U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32))) + CPU_INT32U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return ((CPU_DATA)(CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS)); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT32U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros32(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_DATA)((CPU_WORD_SIZE_32 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros); +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CPU_CntTrailZeros64() +* +* Description : Count the number of contiguous, least-significant, trailing zero bits in a 64-bit data value. +* +* Argument(s) : val Data value to count trailing zero bits. +* +* Return(s) : Number of contiguous, least-significant, trailing zero bits in 'val'. +* +* Note(s) : (1) Supports 64-bit values : +* +* b63 b62 b61 b60 b59 ... b02 b01 b00 # Trailing Zeros +* --- --- --- --- --- --- --- --- ---------------- +* x x x x x x x 1 0 +* x x x x x x 1 0 1 +* x x x x x 1 0 0 2 +* : : : : : : : : : +* : : : : : : : : : +* x x x x 1 0 0 0 59 +* x x x 1 0 0 0 0 60 +* x x 1 0 0 0 0 0 61 +* x 1 0 0 0 0 0 0 62 +* 1 0 0 0 0 0 0 0 63 +* 0 0 0 0 0 0 0 0 64 +* +* +* (2) For non-zero values, the returned number of contiguous, least-significant, trailing +* zero bits is also equivalent to the bit position of the least-significant set bit. +* +* (3) 'val' SHOULD be validated for non-'0' PRIOR to all other counting zero calculations : +* +* (a) For assembly-optimized implementations, CPU_CntTrailZeros() returns 'val's +* number of trailing zeros via CPU's native data size, 'CPU_CFG_DATA_SIZE'. +* If the returned number of zeros exceeds CPU_CntTrailZeros64()'s 64-bit return +* data size, then the returned number of zeros must be offset by the difference +* between CPU_CntTrailZeros()'s & CPU_CntTrailZeros64()'s return data size : +* +* nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); +* if (nbr_trail_zeros > (CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS)) { +* nbr_trail_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_64) * DEF_OCTET_NBR_BITS; +* } +* +* However, this ONLY occurs for an initial 'val' of '0' since all non-'0' 64-bit +* values would return a number of trailing zeros less than or equal to 64 bits. +* +* Therefore, initially validating all non-'0' values prior to calling assembly- +* optimized CPU_CntTrailZeros() avoids having to offset the number of returned +* trailing zeros by the difference in CPU data size and 64-bit data value bits. +* +* (b) For CPU_CntTrailZeros64()'s C implementation, the final conditional statement +* calculates 'val's number of trailing zeros based on CPU_CntTrailZeros64()'s +* 64-bit return data size & 'val's calculated number of lead zeros ONLY if the +* initial 'val' is non-'0' : +* +* if (val != 0u) { +* nbr_trail_zeros = ((CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros; +* } else { +* nbr_trail_zeros = nbr_lead_zeros; +* } +* +* Therefore, initially validating all non-'0' values avoids having to conditionally +* execute the final 'if' statement. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntTrailZeros64 (CPU_INT64U val) +{ +#if (!((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64))) + CPU_INT64U val_bit_mask; + CPU_DATA nbr_lead_zeros; +#endif + CPU_DATA nbr_trail_zeros; + + + if (val == 0u) { /* Rtn ALL val bits as zero'd (see Note #3). */ + return ((CPU_DATA)(CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS)); + } + + /* ------------------ ASM-OPTIMIZED ------------------- */ +#if ((defined(CPU_CFG_TRAIL_ZEROS_ASM_PRESENT)) && \ + (CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_64)) + nbr_trail_zeros = CPU_CntTrailZeros((CPU_DATA)val); + +#else /* ------------------- C-OPTIMIZED -------------------- */ + val_bit_mask = val & ((CPU_INT64U)~val + 1u); /* Zero/clr all bits EXCEPT least-sig set bit. */ + nbr_lead_zeros = CPU_CntLeadZeros64(val_bit_mask); /* Cnt nbr lead 0s. */ + /* Calc nbr trail 0s = (nbr val bits - 1) - nbr lead 0s.*/ + nbr_trail_zeros = ((CPU_DATA)((CPU_WORD_SIZE_64 * DEF_OCTET_NBR_BITS) - 1u) - nbr_lead_zeros); +#endif + + + return (nbr_trail_zeros); +} +#endif + + +/* +********************************************************************************************************* +* CRCUtil_PopCnt_32() +* +* Description : Compute population count (hamming weight) for value (number of bits set). +* +* Argument(s) : value Value to compute population count on. +* +* +* Return(s) : value's population count. +* +* Note(s) : (1) Algorithm taken from en.wikipedia.org/wiki/Hamming_weight +********************************************************************************************************* +*/ + +CPU_INT08U CPU_PopCnt32 (CPU_INT32U value) +{ + CPU_INT32U even_cnt; + CPU_INT32U odd_cnt; + CPU_INT32U result; + + + odd_cnt = (value >> 1u) & CRC_UTIL_POPCNT_MASK01010101_32; /* 2-bits pieces. */ + result = value - odd_cnt; /* Same result as result=odd_cnt+(value & 0x55555555). */ + + even_cnt = result & CRC_UTIL_POPCNT_MASK00110011_32; /* 4-bits pieces. */ + odd_cnt = (result >> 2u) & CRC_UTIL_POPCNT_MASK00110011_32; + result = even_cnt + odd_cnt; + + even_cnt = result & CRC_UTIL_POPCNT_MASK00001111_32; /* 8-bits pieces. */ + odd_cnt = (result >> 4u) & CRC_UTIL_POPCNT_MASK00001111_32; + result = even_cnt + odd_cnt; + + result = (result * CRC_UTIL_POPCNT_POWERSOF256_32) >> 24u; + + return ((CPU_INT08U)result); +} + + +/* +********************************************************************************************************* +* CPU_StatReset() +* +* Description : Reset all performance monitors. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : Critical section provided by caller. +********************************************************************************************************* +*/ + +#if (CPU_CFG_PERF_MON_EN == DEF_ENABLED) +void CPU_StatReset (void) +{ +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_IntDisMeasMax_cnts = 0u; +#endif +} +#endif + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_NameInit() +* +* Description : Initialize CPU Name. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +static void CPU_NameInit (void) +{ + CPU_NameClr(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_TS_Init() +* +* Description : (1) Initialize CPU timestamp : +* +* (a) Initialize/start CPU timestamp timer See Note #1 +* (b) Initialize CPU timestamp controls +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) The following initialization MUST be sequenced as follows : +* +* (a) CPU_TS_TmrFreq_Hz MUST be initialized prior to CPU_TS_TmrInit() +* (b) CPU_TS_TmrInit() SHOULD precede calls to all other CPU timestamp functions; +* otherwise, invalid time measurements may be calculated/ +* returned. +* +* See also 'CPU_Init() Note #3a'. +********************************************************************************************************* +*/ + +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_TMR_EN == DEF_ENABLED)) +static void CPU_TS_Init (void) +{ +#if (((CPU_CFG_TS_32_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) || \ + ((CPU_CFG_TS_64_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64))) + CPU_TS_TMR ts_tmr_cnts; +#endif + + + /* ----------------- INIT CPU TS TMR ------------------ */ +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) + CPU_TS_TmrFreq_Hz = 0u; /* Init/clr ts tmr freq (see Note #1a). */ + CPU_TS_TmrInit(); /* Init & start ts tmr (see Note #1b). */ +#endif + + + /* ------------------- INIT CPU TS -------------------- */ +#if (((CPU_CFG_TS_32_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) || \ + ((CPU_CFG_TS_64_EN == DEF_ENABLED ) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64))) + ts_tmr_cnts = CPU_TS_TmrRd(); /* Get init ts tmr val (in ts tmr cnts). */ +#endif + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) + CPU_TS_32_Accum = 0u; /* Init 32-bit accum'd ts. */ + CPU_TS_32_TmrPrev = ts_tmr_cnts; /* Init 32-bit ts prev tmr val. */ +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) + CPU_TS_64_Accum = 0u; /* Init 64-bit accum'd ts. */ + CPU_TS_64_TmrPrev = ts_tmr_cnts; /* Init 64-bit ts prev tmr val. */ +#endif +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasInit() +* +* Description : (1) Initialize interrupts disabled time measurements feature : +* +* (a) Initialize interrupts disabled time measurement controls +* (b) Calculate interrupts disabled time measurement overhead +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (2) CPU_IntDisMeasInit() SHOULD precede ALL calls to CPU_CRITICAL_ENTER()/CPU_CRITICAL_EXIT() +* & other CPU interrupts disabled time measurement functions; otherwise, invalid interrupts +* disabled time measurements may be calculated/returned. +* +* See also 'CPU_Init() Note #3b'. +* +* (3) (a) (1) Interrupts disabled time measurement overhead performed multiple times to calculate +* a rounded average with better accuracy, hopefully of +/- one timer count. +* +* (2) However, a single overhead time measurement is recommended, even for instruction- +* cache-enabled CPUs, since critical sections are NOT typically called within +* instruction-cached loops. Thus a single non-cached/non-averaged time measurement +* is a more realistic overhead for the majority of non-cached interrupts disabled +* time measurements. +* +* (b) Interrupts MUST be disabled while measuring the interrupts disabled time measurement +* overhead; otherwise, overhead measurements could be interrupted which would incorrectly +* calculate an inflated overhead time which would then incorrectly calculate deflated +* interrupts disabled times. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +static void CPU_IntDisMeasInit (void) +{ + CPU_TS_TMR time_meas_tot_cnts; + CPU_INT16U i; + CPU_SR_ALLOC(); + + /* ----------- INIT INT DIS TIME MEAS CTRLS ----------- */ + CPU_IntDisMeasCtr = 0u; + CPU_IntDisNestCtr = 0u; + CPU_IntDisMeasStart_cnts = 0u; + CPU_IntDisMeasStop_cnts = 0u; + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_IntDisMeasMax_cnts = 0u; + CPU_IntDisMeasOvrhd_cnts = 0u; + + /* ----------- CALC INT DIS TIME MEAS OVRHD ----------- */ + time_meas_tot_cnts = 0u; + CPU_INT_DIS(); /* Ints MUST be dis'd for ovrhd calc (see Note #3b). */ + for (i = 0u; i < CPU_CFG_INT_DIS_MEAS_OVRHD_NBR; i++) { + CPU_IntDisMeasMaxCur_cnts = 0u; + CPU_IntDisMeasStart(); /* Perform multiple consecutive start/stop time meas's */ + CPU_IntDisMeasStop(); + time_meas_tot_cnts += CPU_IntDisMeasMaxCur_cnts; /* ... & sum time meas max's ... */ + } + /* ... to calc avg time meas ovrhd (see Note #3a). */ + CPU_IntDisMeasOvrhd_cnts = (time_meas_tot_cnts + (CPU_CFG_INT_DIS_MEAS_OVRHD_NBR / 2u)) + / CPU_CFG_INT_DIS_MEAS_OVRHD_NBR; + CPU_IntDisMeasMaxCur_cnts = 0u; /* Reset max ints dis'd times. */ + CPU_IntDisMeasMax_cnts = 0u; + CPU_INT_EN(); +} +#endif + + +/* +********************************************************************************************************* +* CPU_IntDisMeasMaxCalc() +* +* Description : Calculate maximum interrupts disabled time. +* +* Argument(s) : time_tot_cnts Total interrupt disabled time, in timer counts. +* +* Return(s) : Maximum interrupts disabled time (in CPU timestamp timer counts). +* +* Note(s) : (1) (a) The total amount of time interrupts are disabled by system &/or application code +* during critical sections is calculated by the following equations : +* +* (1) time = [ time - time ] - time +* interrupts [ stop start ] total meas +* disabled [ meas meas ] ovrhd +* (via application) +* +* +* (2) time = time + time +* total meas start meas stop meas +* ovrhd ovrhd ovrhd +* +* +* where +* +* time time interrupts are disabled between +* interrupts first critical section enter & +* disabled last critical section exit minus +* (via application) time measurement overhead +* +* time time of disable interrupts start time +* start measurement (in timer counts) +* meas +* +* time time of disable interrupts stop time +* stop measurement (in timer counts) +* meas +* +* time total overhead time to start/stop disabled +* total meas interrupts time measurements (in timer +* ovrhd counts) +* +* time total overhead time after getting start +* start meas time until end of start measurement +* ovrhd function (in timer counts) +* +* time total overhead time from beginning of stop +* stop meas measurement function until after getting +* ovrhd stop time (in timer counts) +* +* +* (b) To expedite & reduce interrupts disabled time measurement overhead, the final +* calculations to subtract the interrupts disabled time measurement overhead is +* performed asynchronously in API functions. +* +* See also 'CPU_IntDisMeasStop() Note #1b2'. +* +* (c) The amount of time interrupts are disabled is calculated by either of the +* following equations : +* +* (1) Interrupts disabled time = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Interrupts disabled time Amount of time interrupts are +* disabled, in same units of +* (fractional) seconds as the +* Timer period +* +* Number timer counts +* (2) Interrupts disabled time = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Interrupts disabled time Amount of time interrupts are +* disabled, in seconds +* +* See also 'cpu_core.h FUNCTION PROTOTYPES CPU_TS_TmrRd() Note #2c' +* & 'cpu_core.h FUNCTION PROTOTYPES CPU_TSxx_to_uSec() Note #2'. +* +* (2) Although it is not typical, it is possible for an interrupts disabled time +* measurement to be less than the interrupts disabled time measurement overhead; +* especially if the overhead was calculated with a single, non-cached measurement +* & critical sections are called within instruction-cached loops. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +static CPU_TS_TMR CPU_IntDisMeasMaxCalc (CPU_TS_TMR time_tot_cnts) +{ + CPU_TS_TMR time_max_cnts; + + + time_max_cnts = time_tot_cnts; + if (time_max_cnts > CPU_IntDisMeasOvrhd_cnts) { /* If max ints dis'd time > ovrhd time, ... */ + time_max_cnts -= CPU_IntDisMeasOvrhd_cnts; /* ... adj max ints dis'd time by ovrhd time; ... */ + } else { /* ... else max ints dis'd time < ovrhd time, ... */ + time_max_cnts = 0u; /* ... clr max ints dis'd time (see Note #2). */ + } + + return (time_max_cnts); +} +#endif + diff --git a/rtos/uC-CPU/cpu_core.h b/rtos/uC-CPU/cpu_core.h new file mode 100644 index 00000000..4ad1bb78 --- /dev/null +++ b/rtos/uC-CPU/cpu_core.h @@ -0,0 +1,1031 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CPU MODULE +* +* Filename : cpu_core.h +* Version : V1.32.00 +********************************************************************************************************* +* Note(s) : (1) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/LIB V1.38.02 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This core CPU header file is protected from multiple pre-processor inclusion through use of +* the core CPU module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_CORE_MODULE_PRESENT /* See Note #1. */ +#define CPU_CORE_MODULE_PRESENT + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef CPU_CORE_MODULE +#define CPU_CORE_EXT +#else +#define CPU_CORE_EXT extern +#endif + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_cfg.h +* +* (b) (1) \\cpu_*.* +* (2) \\\\cpu*.* +* +* where +* directory path for Your Product's Application +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (2) NO compiler-supplied standard library functions SHOULD be used. +* +* (a) Standard library functions are implemented in the custom library module(s) : +* +* \\lib_*.* +* +* where +* directory path for custom library software +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #1b1 +* (2) '\\\\' directory See Note #1b2 +* +* (c) '\\' directory See Note #2a +********************************************************************************************************* +*/ + +#include +#include +#include + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +#include +#include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* +********************************************************************************************************* +* CPU CONFIGURATION +* +* Note(s) : (1) The following pre-processor directives correctly configure CPU parameters. DO NOT MODIFY. +* +* (2) CPU timestamp timer feature is required for : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurement +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1'. +********************************************************************************************************* +*/ + +#ifdef CPU_CFG_TS_EN +#undef CPU_CFG_TS_EN +#endif + + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) || \ + (CPU_CFG_TS_64_EN == DEF_ENABLED)) +#define CPU_CFG_TS_EN DEF_ENABLED +#else +#define CPU_CFG_TS_EN DEF_DISABLED +#endif + +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ +(defined(CPU_CFG_INT_DIS_MEAS_EN))) +#define CPU_CFG_TS_TMR_EN DEF_ENABLED +#else +#define CPU_CFG_TS_TMR_EN DEF_DISABLED +#endif + +#if ((CPU_CFG_TS_EN == DEF_ENABLED) || \ +(defined(CPU_CFG_INT_DIS_MEAS_EN))) +#define CPU_CFG_PERF_MON_EN DEF_ENABLED +#else +#define CPU_CFG_PERF_MON_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* CACHE CONFIGURATION +* +* Note(s) : (1) The following pre-processor directives correctly configure CACHE parameters. DO NOT MODIFY. +* +********************************************************************************************************** +*/ + +#ifndef CPU_CFG_CACHE_MGMT_EN +#define CPU_CFG_CACHE_MGMT_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define CPU_TIME_MEAS_NBR_MIN 1u +#define CPU_TIME_MEAS_NBR_MAX 128u + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CPU ERROR CODES +********************************************************************************************************* +*/ + +typedef enum cpu_err { + + CPU_ERR_NONE = 0u, + CPU_ERR_NULL_PTR = 10u, + + CPU_ERR_NAME_SIZE = 1000u, + + CPU_ERR_TS_FREQ_INVALID = 2000u + +} CPU_ERR; + + +/* +********************************************************************************************************* +* CPU TIMESTAMP DATA TYPES +* +* Note(s) : (1) CPU timestamp timer data type defined to the binary-multiple of 8-bit octets as configured +* by 'CPU_CFG_TS_TMR_SIZE' (see 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2'). +********************************************************************************************************* +*/ + +typedef CPU_INT32U CPU_TS32; +typedef CPU_INT64U CPU_TS64; + +typedef CPU_TS32 CPU_TS; /* Req'd for backwards-compatibility. */ + + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) /* CPU ts tmr defined to cfg'd word size (see Note #1). */ +#if (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_08) +typedef CPU_INT08U CPU_TS_TMR; +#elif (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_16) +typedef CPU_INT16U CPU_TS_TMR; +#elif (CPU_CFG_TS_TMR_SIZE == CPU_WORD_SIZE_64) +typedef CPU_INT64U CPU_TS_TMR; +#else /* CPU ts tmr dflt size = 32-bits. */ +typedef CPU_INT32U CPU_TS_TMR; +#endif +#endif + + +/* +********************************************************************************************************* +* CPU TIMESTAMP TIMER FREQUENCY DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_INT32U CPU_TS_TMR_FREQ; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) +CPU_CORE_EXT CPU_CHAR CPU_Name[CPU_CFG_NAME_SIZE]; /* CPU host name. */ +#endif + + +#if ((CPU_CFG_TS_32_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)) +CPU_CORE_EXT CPU_TS32 CPU_TS_32_Accum; /* 32-bit accum'd ts (in ts tmr cnts). */ +CPU_CORE_EXT CPU_TS_TMR CPU_TS_32_TmrPrev; /* 32-bit ts prev tmr (in ts tmr cnts). */ +#endif + +#if ((CPU_CFG_TS_64_EN == DEF_ENABLED) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_64)) +CPU_CORE_EXT CPU_TS64 CPU_TS_64_Accum; /* 64-bit accum'd ts (in ts tmr cnts). */ +CPU_CORE_EXT CPU_TS_TMR CPU_TS_64_TmrPrev; /* 64-bit ts prev tmr (in ts tmr cnts). */ +#endif + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_CORE_EXT CPU_TS_TMR_FREQ CPU_TS_TmrFreq_Hz; /* CPU ts tmr freq (in Hz). */ +#endif + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +CPU_CORE_EXT CPU_INT16U CPU_IntDisMeasCtr; /* Nbr tot ints dis'd ctr. */ +CPU_CORE_EXT CPU_INT16U CPU_IntDisNestCtr; /* Nbr nested ints dis'd ctr. */ + /* Ints dis'd time (in ts tmr cnts) : ... */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasStart_cnts; /* ... start time. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasStop_cnts; /* ... stop time. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasOvrhd_cnts; /* ... time meas ovrhd. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasMaxCur_cnts; /* ... resetable max time dis'd. */ +CPU_CORE_EXT CPU_TS_TMR CPU_IntDisMeasMax_cnts; /* ... non-resetable max time dis'd. */ +#endif + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_SW_EXCEPTION() +* +* Description : Trap unrecoverable software exception. +* +* Argument(s) : err_rtn_val Error type &/or value of the calling function to return (see Note #2b). +* +* Return(s) : none. +* +* Note(s) : (1) CPU_SW_EXCEPTION() deadlocks the current code execution -- whether multi-tasked/ +* -processed/-threaded or single-threaded -- when the current code execution cannot +* gracefully recover or report a fault or exception condition. +* +* Example CPU_SW_EXCEPTION() call : +* +* void Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { If 'p_err' NULL, cannot return error ... +* CPU_SW_EXCEPTION(;); ... so trap invalid argument exception. +* } +* +* : +* } +* +* See also 'cpu_core.c CPU_SW_Exception() Note #1'. +* +* (2) (a) CPU_SW_EXCEPTION() MAY be developer-implemented to output &/or handle any error or +* exception conditions; but since CPU_SW_EXCEPTION() is intended to trap unrecoverable +* software conditions, it is recommended that developer-implemented versions prevent +* execution of any code following calls to CPU_SW_EXCEPTION() by deadlocking the code +* (see Note #1). +* +* Example CPU_SW_EXCEPTION() : +* +* #define CPU_SW_EXCEPTION(err_rtn_val) do { \ +* Log(__FILE__, __LINE__); \ +* CPU_SW_Exception(); \ +* } while (0) +* +* (b) (1) However, if execution of code following calls to CPU_SW_EXCEPTION() is required +* (e.g. for automated testing); it is recommended that the last statement in +* developer-implemented versions be to return from the current function to prevent +* possible software exception(s) in the current function from triggering CPU &/or +* hardware exception(s). +* +* Example CPU_SW_EXCEPTION() : +* +* #define CPU_SW_EXCEPTION(err_rtn_val) do { \ +* Log(__FILE__, __LINE__); \ +* return err_rtn_val; \ +* } while (0) +* +* (A) Note that 'err_rtn_val' in the return statement MUST NOT be enclosed in +* parentheses. This allows CPU_SW_EXCEPTION() to return from functions that +* return 'void', i.e. NO return type or value (see also Note #2b2A). +* +* (2) In order for CPU_SW_EXCEPTION() to return from functions with various return +* types/values, each caller function MUST pass an appropriate error return type +* & value to CPU_SW_EXCEPTION(). +* +* (A) Note that CPU_SW_EXCEPTION() MUST NOT be passed any return type or value +* for functions that return 'void', i.e. NO return type or value; but SHOULD +* instead be passed a single semicolon. This prevents possible compiler +* warnings that CPU_SW_EXCEPTION() is passed too few arguments. However, +* the compiler may warn that CPU_SW_EXCEPTION() does NOT prevent creating +* null statements on lines with NO other code statements. +* +* Example CPU_SW_EXCEPTION() calls : +* +* void Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION(;); Exception macro returns NO value +* } (see Note #2b2A) +* +* : +* } +* +* CPU_BOOLEAN Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION(DEF_FAIL); Exception macro returns 'DEF_FAIL' +* } +* +* : +* } +* +* OBJ *Fnct (CPU_ERR *p_err) +* { +* : +* +* if (p_err == (CPU_ERR *)0) { +* CPU_SW_EXCEPTION((OBJ *)0); Exception macro returns NULL 'OBJ *' +* } +* +* : +* } +* +********************************************************************************************************* +*/ + +#ifndef CPU_SW_EXCEPTION /* See Note #2. */ +#define CPU_SW_EXCEPTION(err_rtn_val) do { \ + CPU_SW_Exception(); \ + } while (0) +#endif + + +/* +********************************************************************************************************* +* CPU_VAL_UNUSED() +* +* Description : Suppresses unused variable warnings. +* +* Argument(s) : none. +* +* Return(s) : none. +* + Note(s) : none. +********************************************************************************************************* +*/ + + +#define CPU_VAL_UNUSED(val) ((void)(val)); + + +#define CPU_VAL_IGNORED(val) CPU_VAL_UNUSED(val) + + +/* +********************************************************************************************************* +* CPU_TYPE_CREATE() +* +* Description : Creates a generic type value. +* +* Argument(s) : char_1 1st ASCII character to create generic type value. +* +* char_2 2nd ASCII character to create generic type value. +* +* char_3 3rd ASCII character to create generic type value. +* +* char_4 4th ASCII character to create generic type value. +* +* Return(s) : 32-bit generic type value. +* +* Note(s) : (1) (a) Generic type values should be #define'd with large, non-trivial values to trap +* & discard invalid/corrupted objects based on type value. +* +* In other words, by assigning large, non-trivial values to valid objects' type +* fields; the likelihood that an object with an unassigned &/or corrupted type +* field will contain a value is highly improbable & therefore the object itself +* will be trapped as invalid. +* +* (b) (1) CPU_TYPE_CREATE() creates a 32-bit type value from four values. +* +* (2) Ideally, generic type values SHOULD be created from 'CPU_CHAR' characters to +* represent ASCII string abbreviations of the specific object types. Memory +* displays of object type values will display the specific object types with +* their chosen ASCII names. +* +* Examples : +* +* #define FILE_TYPE CPU_TYPE_CREATE('F', 'I', 'L', 'E') +* #define BUF_TYPE CPU_TYPE_CREATE('B', 'U', 'F', ' ') +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)))) + +#else + +#if ((CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) || \ + (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32)) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1))) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)) << (3u * DEF_OCTET_NBR_BITS))) + + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3))) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)) << (1u * DEF_OCTET_NBR_BITS))) + +#else /* Dflt CPU_WORD_SIZE_08. */ +#define CPU_TYPE_CREATE(char_1, char_2, char_3, char_4) (((CPU_INT32U)((CPU_INT08U)(char_1)) << (3u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_2)) << (2u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_3)) << (1u * DEF_OCTET_NBR_BITS)) | \ + ((CPU_INT32U)((CPU_INT08U)(char_4)))) +#endif +#endif + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* +* Note(s) : (1) CPU interrupts disabled time measurement functions prototyped/defined only if +* CPU_CFG_INT_DIS_MEAS_EN #define'd in 'cpu_cfg.h'. +* +* (2) (a) CPU_CntLeadZeros() defined in : +* +* (1) 'cpu_a.asm', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_LEAD_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) +* +* (b) CPU_CntTrailZeros() defined in : +* +* (1) 'cpu_a.asm', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable assembly-optimized function(s) +* +* (2) 'cpu_core.c', if CPU_CFG_TRAIL_ZEROS_ASM_PRESENT NOT #define'd in 'cpu.h'/ +* 'cpu_cfg.h' to enable C-source-optimized function(s) +********************************************************************************************************* +*/ + +void CPU_Init (void); + +void CPU_SW_Exception (void); + + + +#if (CPU_CFG_NAME_EN == DEF_ENABLED) /* -------------- CPU NAME FNCTS -------------- */ +void CPU_NameClr (void); + +void CPU_NameGet ( CPU_CHAR *p_name, + CPU_ERR *p_err); + +void CPU_NameSet (const CPU_CHAR *p_name, + CPU_ERR *p_err); +#endif + + + + /* --------------- CPU TS FNCTS --------------- */ +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_TS32 CPU_TS_Get32 (void); +#endif + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_TS64 CPU_TS_Get64 (void); +#endif + +#if (CPU_CFG_TS_EN == DEF_ENABLED) +void CPU_TS_Update (void); +#endif + + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) /* ------------- CPU TS TMR FNCTS ------------- */ +CPU_TS_TMR_FREQ CPU_TS_TmrFreqGet (CPU_ERR *p_err); + +void CPU_TS_TmrFreqSet (CPU_TS_TMR_FREQ freq_hz); +#endif + + + +#ifdef CPU_CFG_INT_DIS_MEAS_EN /* -------- CPU INT DIS TIME MEAS FNCTS ------- */ + /* See Note #1. */ +CPU_TS_TMR CPU_IntDisMeasMaxCurReset(void); + +CPU_TS_TMR CPU_IntDisMeasMaxCurGet (void); + +CPU_TS_TMR CPU_IntDisMeasMaxGet (void); + + +void CPU_IntDisMeasStart (void); + +void CPU_IntDisMeasStop (void); +#endif + + + + /* ----------- CPU CNT ZEROS FNCTS ------------ */ +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +extern "C" { +#endif +#endif + +CPU_DATA CPU_CntLeadZeros (CPU_DATA val); + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +} +#endif +#endif + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntLeadZeros08 (CPU_INT08U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntLeadZeros16 (CPU_INT16U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntLeadZeros32 (CPU_INT32U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntLeadZeros64 (CPU_INT64U val); +#endif + + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +extern "C" { +#endif +#endif + +CPU_DATA CPU_CntTrailZeros (CPU_DATA val); + +#ifdef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#ifdef __cplusplus +} +#endif +#endif + +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_08) +CPU_DATA CPU_CntTrailZeros08 (CPU_INT08U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_16) +CPU_DATA CPU_CntTrailZeros16 (CPU_INT16U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32) +CPU_DATA CPU_CntTrailZeros32 (CPU_INT32U val); +#endif +#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_64) +CPU_DATA CPU_CntTrailZeros64 (CPU_INT64U val); +#endif + +CPU_INT08U CPU_PopCnt32 (CPU_INT32U value); + + /* ------------ CPU PERF MON RESET ------------ */ +#if (CPU_CFG_PERF_MON_EN == DEF_ENABLED) +void CPU_StatReset (void); +#endif + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* DEFINED IN PRODUCT'S BSP +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CPU_TS_TmrInit() +* +* Description : Initialize & start CPU timestamp timer. +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Note(s) : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (c) When applicable, timer period SHOULD be less than the typical measured time +* but MUST be less than the maximum measured time; otherwise, timer resolution +* inadequate to measure desired times. +* +* See also 'CPU_TS_TmrRd() Note #2'. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +void CPU_TS_TmrInit(void); +#endif + + +/* +********************************************************************************************************* +* CPU_TS_TmrRd() +* +* Description : Get current CPU timestamp timer count value. +* +* Argument(s) : none. +* +* Return(s) : Timestamp timer count (see Notes #2a & #2b). +* +* Note(s) : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer +* if either of the following CPU features is enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR' +* data type. +* +* (1) If timer has more bits, truncate timer values' higher-order bits greater +* than the configured 'CPU_TS_TMR' timestamp timer data type word size. +* +* (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR' +* timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be +* configured so that ALL bits in 'CPU_TS_TMR' data type are significant. +* +* In other words, if timer size is not a binary-multiple of 8-bit octets +* (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple +* octet word size SHOULD be configured (e.g. to 16-bits). However, the +* minimum supported word size for CPU timestamp timers is 8-bits. +* +* See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2' +* & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'. +* +* (b) Timer SHOULD be an 'up' counter whose values increase with each time count. +* +* (1) If timer is a 'down' counter whose values decrease with each time count, +* then the returned timer value MUST be ones-complemented. +* +* (c) (1) When applicable, the amount of time measured by CPU timestamps is +* calculated by either of the following equations : +* +* (A) Time measured = Number timer counts * Timer period +* +* where +* +* Number timer counts Number of timer counts measured +* Timer period Timer's period in some units of +* (fractional) seconds +* Time measured Amount of time measured, in same +* units of (fractional) seconds +* as the Timer period +* +* Number timer counts +* (B) Time measured = --------------------- +* Timer frequency +* +* where +* +* Number timer counts Number of timer counts measured +* Timer frequency Timer's frequency in some units +* of counts per second +* Time measured Amount of time measured, in seconds +* +* (2) Timer period SHOULD be less than the typical measured time but MUST be less +* than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED) +CPU_TS_TMR CPU_TS_TmrRd(void); +#endif + + +/* +********************************************************************************************************* +* CPU_TSxx_to_uSec() +* +* Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds. +* +* Argument(s) : ts_cnts CPU timestamp (in timestamp timer counts [see Note #2aA]). +* +* Return(s) : Converted CPU timestamp (in microseconds [see Note #2aD]). +* +* Note(s) : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be +* optionally defined by the developer when either of the following CPU features is +* enabled : +* +* (a) CPU timestamps +* (b) CPU interrupts disabled time measurements +* +* See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1' +* & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'. +* +* (2) (a) The amount of time measured by CPU timestamps is calculated by either of +* the following equations : +* +* 10^6 microseconds +* (1) Time measured = Number timer counts * ------------------- * Timer period +* 1 second +* +* Number timer counts 10^6 microseconds +* (2) Time measured = --------------------- * ------------------- +* Timer frequency 1 second +* +* where +* +* (A) Number timer counts Number of timer counts measured +* (B) Timer frequency Timer's frequency in some units +* of counts per second +* (C) Timer period Timer's period in some units of +* (fractional) seconds +* (D) Time measured Amount of time measured, +* in microseconds +* +* (b) Timer period SHOULD be less than the typical measured time but MUST be less +* than the maximum measured time; otherwise, timer resolution inadequate to +* measure desired times. +* +* (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits +* -- up to 32 or 64, respectively -- into microseconds. +********************************************************************************************************* +*/ + +#if (CPU_CFG_TS_32_EN == DEF_ENABLED) +CPU_INT64U CPU_TS32_to_uSec(CPU_TS32 ts_cnts); +#endif + +#if (CPU_CFG_TS_64_EN == DEF_ENABLED) +CPU_INT64U CPU_TS64_to_uSec(CPU_TS64 ts_cnts); +#endif + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_NAME_EN +#error "CPU_CFG_NAME_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_ENABLED ] " +#error " [ || DEF_DISABLED] " + +#elif ((CPU_CFG_NAME_EN != DEF_ENABLED ) && \ + (CPU_CFG_NAME_EN != DEF_DISABLED)) +#error "CPU_CFG_NAME_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_ENABLED ] " +#error " [ || DEF_DISABLED] " + + +#elif (CPU_CFG_NAME_EN == DEF_ENABLED) + +#ifndef CPU_CFG_NAME_SIZE +#error "CPU_CFG_NAME_SIZE not #define'd in 'cpu_cfg.h'" +#error " [MUST be >= 1] " +#error " [ && <= 255] " + +#elif (DEF_CHK_VAL(CPU_CFG_NAME_SIZE, \ + 1, \ + DEF_INT_08U_MAX_VAL) != DEF_OK) +#error "CPU_CFG_NAME_SIZE illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be >= 1] " +#error " [ && <= 255] " +#endif + +#endif + + + + +#ifndef CPU_CFG_TS_32_EN +#error "CPU_CFG_TS_32_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_32_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_32_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_32_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + +#ifndef CPU_CFG_TS_64_EN +#error "CPU_CFG_TS_64_EN not #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_64_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_64_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_64_EN illegally #define'd in 'cpu_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + /* Correctly configured in 'cpu_core.h'; DO NOT MODIFY. */ +#ifndef CPU_CFG_TS_EN +#error "CPU_CFG_TS_EN not #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_EN illegally #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#endif + + + /* Correctly configured in 'cpu_core.h'; DO NOT MODIFY. */ +#ifndef CPU_CFG_TS_TMR_EN +#error "CPU_CFG_TS_TMR_EN not #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((CPU_CFG_TS_TMR_EN != DEF_DISABLED) && \ + (CPU_CFG_TS_TMR_EN != DEF_ENABLED )) +#error "CPU_CFG_TS_TMR_EN illegally #define'd in 'cpu_core.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + + +#elif (CPU_CFG_TS_TMR_EN == DEF_ENABLED) + +#ifndef CPU_CFG_TS_TMR_SIZE +#error "CPU_CFG_TS_TMR_SIZE not #define'd in 'cpu_cfg.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit timer]" +#error " [ || CPU_WORD_SIZE_16 16-bit timer]" +#error " [ || CPU_WORD_SIZE_32 32-bit timer]" +#error " [ || CPU_WORD_SIZE_64 64-bit timer]" + +#elif ((CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_08) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_16) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_32) && \ + (CPU_CFG_TS_TMR_SIZE != CPU_WORD_SIZE_64)) +#error "CPU_CFG_TS_TMR_SIZE illegally #define'd in 'cpu_cfg.h' " +#error " [MUST be CPU_WORD_SIZE_08 8-bit timer]" +#error " [ || CPU_WORD_SIZE_16 16-bit timer]" +#error " [ || CPU_WORD_SIZE_32 32-bit timer]" +#error " [ || CPU_WORD_SIZE_64 64-bit timer]" +#endif + +#endif + + + +#ifndef CPU_CFG_INT_DIS_MEAS_EN +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_INT_DIS_MEAS_EN not #define'd in 'cpu_cfg.h'" +#endif + +#else + +#ifndef CPU_CFG_INT_DIS_MEAS_OVRHD_NBR +#error "CPU_CFG_INT_DIS_MEAS_OVRHD_NBR not #define'd in 'cpu_cfg.h' " +#error " [MUST be >= CPU_TIME_MEAS_NBR_MIN]" +#error " [ || <= CPU_TIME_MEAS_NBR_MAX]" + +#elif (DEF_CHK_VAL(CPU_CFG_INT_DIS_MEAS_OVRHD_NBR, \ + CPU_TIME_MEAS_NBR_MIN, \ + CPU_TIME_MEAS_NBR_MAX) != DEF_OK) +#error "CPU_CFG_INT_DIS_MEAS_OVRHD_NBR illegally #define'd in 'cpu_cfg.h' " +#error " [MUST be >= CPU_TIME_MEAS_NBR_MIN]" +#error " [ || <= CPU_TIME_MEAS_NBR_MAX]" + +#endif + +#endif + + + + +#ifndef CPU_CFG_LEAD_ZEROS_ASM_PRESENT +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_LEAD_ZEROS_ASM_PRESENT not #define'd in 'cpu.h'/'cpu_cfg.h'" +#endif +#endif + + +#ifndef CPU_CFG_TRAIL_ZEROS_ASM_PRESENT +#if 0 /* Optionally configured in 'cpu_cfg.h'; DO NOT MODIFY. */ +#error "CPU_CFG_TRAIL_ZEROS_ASM_PRESENT not #define'd in 'cpu.h'/'cpu_cfg.h'" +#endif +#endif + + +/* +********************************************************************************************************* +* CPU PORT CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef CPU_CFG_ADDR_SIZE +#error "CPU_CFG_ADDR_SIZE not #define'd in 'cpu.h'" +#endif + +#ifndef CPU_CFG_DATA_SIZE +#error "CPU_CFG_DATA_SIZE not #define'd in 'cpu.h'" +#endif + +#ifndef CPU_CFG_DATA_SIZE_MAX +#error "CPU_CFG_DATA_SIZE_MAX not #define'd in 'cpu.h'" +#endif + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'cpu_core.h Note #1a'. */ +#if (LIB_VERSION < 13802u) +#error "LIB_VERSION [SHOULD be >= V1.38.02]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu_core.h MODULE'. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} +#endif +#endif /* End of CPU core module include. */ + diff --git a/rtos/uC-CPU/cpu_def.h b/rtos/uC-CPU/cpu_def.h new file mode 100644 index 00000000..58891d56 --- /dev/null +++ b/rtos/uC-CPU/cpu_def.h @@ -0,0 +1,212 @@ +/* +********************************************************************************************************* +* uC/CPU +* CPU CONFIGURATION & PORT LAYER +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CPU CONFIGURATION DEFINES +* +* Filename : cpu_def.h +* Version : v1.32.00 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This CPU definition header file is protected from multiple pre-processor inclusion +* through use of the CPU definition module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef CPU_DEF_MODULE_PRESENT +#define CPU_DEF_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CORE CPU MODULE VERSION NUMBER +* +* Note(s) : (1) (a) The core CPU module software version is denoted as follows : +* +* Vx.yy.zz +* +* where +* V denotes 'Version' label +* x denotes major software version revision number +* yy denotes minor software version revision number +* zz denotes sub-minor software version revision number +* +* (b) The software version label #define is formatted as follows : +* +* ver = x.yyzz * 100 * 100 +* +* where +* ver denotes software version number scaled as an integer value +* x.yyzz denotes software version number, where the unscaled integer +* portion denotes the major version number & the unscaled +* fractional portion denotes the (concatenated) minor +* version numbers +********************************************************************************************************* +*/ + +#define CPU_CORE_VERSION 13200u /* See Note #1. */ + + +/* +********************************************************************************************************* +* CPU WORD CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_ADDR_SIZE & CPU_CFG_DATA_SIZE in 'cpu.h' with CPU's word sizes : +* +* CPU_WORD_SIZE_08 8-bit word size +* CPU_WORD_SIZE_16 16-bit word size +* CPU_WORD_SIZE_32 32-bit word size +* CPU_WORD_SIZE_64 64-bit word size +* +* (2) Configure CPU_CFG_ENDIAN_TYPE in 'cpu.h' with CPU's data-word-memory order : +* +* (a) CPU_ENDIAN_TYPE_BIG Big- endian word order (CPU words' most significant +* octet @ lowest memory address) +* (b) CPU_ENDIAN_TYPE_LITTLE Little-endian word order (CPU words' least significant +* octet @ lowest memory address) +********************************************************************************************************* +*/ + + /* ---------------------- CPU WORD SIZE ----------------------- */ +#define CPU_WORD_SIZE_08 1u /* 8-bit word size (in octets). */ +#define CPU_WORD_SIZE_16 2u /* 16-bit word size (in octets). */ +#define CPU_WORD_SIZE_32 4u /* 32-bit word size (in octets). */ +#define CPU_WORD_SIZE_64 8u /* 64-bit word size (in octets). */ + + + /* ------------------ CPU WORD-ENDIAN ORDER ------------------- */ +#define CPU_ENDIAN_TYPE_NONE 0u +#define CPU_ENDIAN_TYPE_BIG 1u /* Big- endian word order (see Note #1a). */ +#define CPU_ENDIAN_TYPE_LITTLE 2u /* Little-endian word order (see Note #1b). */ + + +/* +********************************************************************************************************* +* CPU STACK CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_STK_GROWTH in 'cpu.h' with CPU's stack growth order : +* +* (a) CPU_STK_GROWTH_LO_TO_HI CPU stack pointer increments to the next higher stack +* memory address after data is pushed onto the stack +* (b) CPU_STK_GROWTH_HI_TO_LO CPU stack pointer decrements to the next lower stack +* memory address after data is pushed onto the stack +********************************************************************************************************* +*/ + + /* ------------------ CPU STACK GROWTH ORDER ------------------ */ +#define CPU_STK_GROWTH_NONE 0u +#define CPU_STK_GROWTH_LO_TO_HI 1u /* CPU stk incs towards higher mem addrs (see Note #1a). */ +#define CPU_STK_GROWTH_HI_TO_LO 2u /* CPU stk decs towards lower mem addrs (see Note #1b). */ + + +/* +********************************************************************************************************* +* CRITICAL SECTION CONFIGURATION +* +* Note(s) : (1) Configure CPU_CFG_CRITICAL_METHOD with CPU's/compiler's critical section method : +* +* Enter/Exit critical sections by ... +* +* CPU_CRITICAL_METHOD_INT_DIS_EN Disable/Enable interrupts +* CPU_CRITICAL_METHOD_STATUS_STK Push/Pop interrupt status onto stack +* CPU_CRITICAL_METHOD_STATUS_LOCAL Save/Restore interrupt status to local variable +* +* (a) CPU_CRITICAL_METHOD_INT_DIS_EN is NOT a preferred method since it does NOT support +* multiple levels of interrupts. However, with some CPUs/compilers, this is the only +* available method. +* +* (b) CPU_CRITICAL_METHOD_STATUS_STK is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Push/save interrupt status onto a local stack +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Pop/restore interrupt status from a local stack +* +* (c) CPU_CRITICAL_METHOD_STATUS_LOCAL is one preferred method since it supports multiple +* levels of interrupts. However, this method assumes that the compiler provides C-level +* &/or assembly-level functionality for the following : +* +* ENTER CRITICAL SECTION : +* (1) Save interrupt status into a local variable +* (2) Disable interrupts +* +* EXIT CRITICAL SECTION : +* (3) Restore interrupt status from a local variable +* +* (2) Critical section macro's most likely require inline assembly. If the compiler does NOT +* allow inline assembly in C source files, critical section macro's MUST call an assembly +* subroutine defined in a 'cpu_a.asm' file located in the following software directory : +* +* \\\\ +* +* where +* directory path for common CPU-compiler software +* directory name for specific CPU +* directory name for specific compiler +* +* (3) (a) To save/restore interrupt status, a local variable 'cpu_sr' of type 'CPU_SR' MAY need +* to be declared (e.g. if 'CPU_CRITICAL_METHOD_STATUS_LOCAL' method is configured). +* +* (1) 'cpu_sr' local variable SHOULD be declared via the CPU_SR_ALLOC() macro which, +* if used, MUST be declared following ALL other local variables (see any 'cpu.h +* CRITICAL SECTION CONFIGURATION Note #3a1'). +* +* Example : +* +* void Fnct (void) +* { +* CPU_INT08U val_08; +* CPU_INT16U val_16; +* CPU_INT32U val_32; +* CPU_SR_ALLOC(); MUST be declared after ALL other local variables +* : +* : +* } +* +* (b) Configure 'CPU_SR' data type with the appropriate-sized CPU data type large enough to +* completely store the CPU's/compiler's status word. +********************************************************************************************************* +*/ + + /* --------------- CPU CRITICAL SECTION METHODS --------------- */ +#define CPU_CRITICAL_METHOD_NONE 0u /* */ +#define CPU_CRITICAL_METHOD_INT_DIS_EN 1u /* DIS/EN ints (see Note #1a). */ +#define CPU_CRITICAL_METHOD_STATUS_STK 2u /* Push/Pop int status onto stk (see Note #1b). */ +#define CPU_CRITICAL_METHOD_STATUS_LOCAL 3u /* Save/Restore int status to local var (see Note #1c). */ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'cpu_def.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of CPU def module include. */ + diff --git a/rtos/uC-CPU/readme.md b/rtos/uC-CPU/readme.md new file mode 100644 index 00000000..8301a49c --- /dev/null +++ b/rtos/uC-CPU/readme.md @@ -0,0 +1,5 @@ +# uC/CPU + +Designed with Micriμm’s renowned quality, scalability and reliability, the purpose of μC/ CPU is to provide a clean, organized ANSI C implementation of each processor’s/ compiler’s hardware-dependent. + +## For the complete documentation, visit https://doc.micrium.com/display/ucos/ \ No newline at end of file diff --git a/rtos/uC-LIB/Cfg/lib_cfg.h b/rtos/uC-LIB/Cfg/lib_cfg.h new file mode 100644 index 00000000..3379143c --- /dev/null +++ b/rtos/uC-LIB/Cfg/lib_cfg.h @@ -0,0 +1,163 @@ +/* +********************************************************************************************************* +* EXAMPLE CODE +* +* This file is provided as an example on how to use Micrium products. +* +* Please feel free to use any application code labeled as 'EXAMPLE CODE' in +* your application products. Example code may be used as is, in whole or in +* part, or may be used as a reference only. This file can be modified as +* required to meet the end-product requirements. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CUSTOM LIBRARY CONFIGURATION FILE +* +* TEMPLATE +* +* Filename : lib_cfg.h +* Version : V1.39.00 +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +********************************************************************************************************* +*/ + +#ifndef LIB_CFG_MODULE_PRESENT +#define LIB_CFG_MODULE_PRESENT + + +/* +********************************************************************************************************* +********************************************************************************************************* +* MEMORY LIBRARY CONFIGURATION +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY LIBRARY ARGUMENT CHECK CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_ARG_CHK_EXT_EN to enable/disable the memory library suite external +* argument check feature : +* +* (a) When ENABLED, arguments received from any port interface provided by the developer +* or application are checked/validated. +* +* (b) When DISABLED, NO arguments received from any port interface provided by the developer +* or application are checked/validated. +********************************************************************************************************* +*/ + + /* External argument check. */ + /* Indicates if arguments received from any port ... */ + /* ... interface provided by the developer or ... */ + /* ... application are checked/validated. */ +#define LIB_MEM_CFG_ARG_CHK_EXT_EN DEF_DISABLED + + +/* +********************************************************************************************************* +* MEMORY LIBRARY ASSEMBLY OPTIMIZATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_OPTIMIZE_ASM_EN to enable/disable assembly-optimized memory function(s). +********************************************************************************************************* +*/ + + /* Assembly-optimized function(s). */ + /* Enable/disable assembly-optimized memory ... */ + /* ... function(s). [see Note #1] */ +#define LIB_MEM_CFG_OPTIMIZE_ASM_EN DEF_DISABLED + + +/* +********************************************************************************************************* +* MEMORY ALLOCATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_DBG_INFO_EN to enable/disable memory allocation usage tracking +* that associates a name with each segment or dynamic pool allocated. +* +* (2) (a) Configure LIB_MEM_CFG_HEAP_SIZE with the desired size of heap memory (in octets). +* +* (b) Configure LIB_MEM_CFG_HEAP_BASE_ADDR to specify a base address for heap memory : +* +* (1) Heap initialized to specified application memory, if LIB_MEM_CFG_HEAP_BASE_ADDR +* #define'd in 'lib_cfg.h'; +* CANNOT #define to address 0x0 +* +* (2) Heap declared to Mem_Heap[] in 'lib_mem.c', if LIB_MEM_CFG_HEAP_BASE_ADDR +* NOT #define'd in 'lib_cfg.h' +********************************************************************************************************* +*/ + + /* Allocation debugging information. */ + /* Enable/disable allocation of debug information ... */ + /* ... associated to each memory allocation. */ +#define LIB_MEM_CFG_DBG_INFO_EN DEF_DISABLED + + + /* Heap memory size (in bytes). */ + /* Configure the desired size of the heap memory. ... */ + /* ... Set to 0 to disable heap allocation features. */ +#define LIB_MEM_CFG_HEAP_SIZE 1024u + + + /* Heap memory padding alignment (in bytes). */ + /* Configure the desired size of padding alignment ... */ + /* ... of each buffer allocated from the heap. */ +#define LIB_MEM_CFG_HEAP_PADDING_ALIGN LIB_MEM_PADDING_ALIGN_NONE + +#if 0 /* Remove this to have heap alloc at specified addr. */ +#define LIB_MEM_CFG_HEAP_BASE_ADDR 0x00000000 /* Configure heap memory base address (see Note #2b). */ +#endif + + +/* +********************************************************************************************************* +********************************************************************************************************* +* STRING LIBRARY CONFIGURATION +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STRING FLOATING POINT CONFIGURATION +* +* Note(s) : (1) Configure LIB_STR_CFG_FP_EN to enable/disable floating point string function(s). +* +* (2) Configure LIB_STR_CFG_FP_MAX_NBR_DIG_SIG to configure the maximum number of significant +* digits to calculate &/or display for floating point string function(s). +* +* See also 'lib_str.h STRING FLOATING POINT DEFINES Note #1'. +********************************************************************************************************* +*/ + + /* Floating point feature(s). */ + /* Enable/disable floating point to string functions. */ +#define LIB_STR_CFG_FP_EN DEF_DISABLED + + + /* Floating point number of significant digits. */ + /* Configure the maximum number of significant ... */ + /* ... digits to calculate &/or display for ... */ + /* ... floating point string function(s). */ +#define LIB_STR_CFG_FP_MAX_NBR_DIG_SIG LIB_STR_FP_MAX_NBR_DIG_SIG_DFLT + + +/* +********************************************************************************************************* +* MODULE END +********************************************************************************************************* +*/ + +#endif /* End of lib cfg module include. */ + diff --git a/rtos/uC-LIB/LICENSE b/rtos/uC-LIB/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/rtos/uC-LIB/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/rtos/uC-LIB/NOTICE b/rtos/uC-LIB/NOTICE new file mode 100644 index 00000000..e8cacd2c --- /dev/null +++ b/rtos/uC-LIB/NOTICE @@ -0,0 +1,28 @@ +ATTENTION ALL USERS OF THIS REPOSITORY: + +The original work found in this repository is provided by Silicon Labs under the +Apache License, Version 2.0. + +Any third party may contribute derivative works to the original work in which +modifications are clearly identified as being licensed under: + + (1) the Apache License, Version 2.0 or a compatible open source license; or + (2) under a proprietary license with a copy of such license deposited. + +All posted derivative works must clearly identify which license choice has been +elected. + +No such posted derivative works will be considered to be a “Contribution” under +the Apache License, Version 2.0. + +SILICON LABS MAKES NO WARRANTY WITH RESPECT TO ALL POSTED THIRD PARTY CONTENT +AND DISCLAIMS ALL OTHER WARRANTIES OR LIABILITIES, INCLUDING ALL WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OWNERSHIP, +NON-INFRINGEMENT, AND NON-MISAPPROPRIATION. + +In the event a derivative work is desired to be submitted to Silicon Labs as a +“Contribution” under the Apache License, Version 2.0, a “Contributor” must give +written email notice to micrium@weston-embedded.com. Unless an email response in +the affirmative to accept the derivative work as a “Contribution”, such email +submission should be considered to have not been incorporated into the original +work. diff --git a/rtos/uC-LIB/Ports/ARM-Cortex-M3/lib_mem_a.s b/rtos/uC-LIB/Ports/ARM-Cortex-M3/lib_mem_a.s new file mode 100644 index 00000000..c257603b --- /dev/null +++ b/rtos/uC-LIB/Ports/ARM-Cortex-M3/lib_mem_a.s @@ -0,0 +1,298 @@ +@******************************************************************************************************** +@ uC/LIB +@ Custom Library Modules +@ +@ Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + + +@******************************************************************************************************** +@ +@ STANDARD MEMORY OPERATIONS +@ +@ ARM-Cortex-M3 +@ GNU Compiler +@ +@ Filename : lib_mem_a.s +@ Version : V1.39.00 +@******************************************************************************************************** +@ Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +@ +@ (a) ALL standard library functions are implemented in the custom library modules : +@ +@ (1) \\lib*.* +@ +@ (2) \\Ports\\\lib*_a.* +@ +@ where +@ directory path for custom library software +@ directory name for specific processor (CPU) +@ directory name for specific compiler +@ +@ (b) Product-specific library functions are implemented in individual products. +@ +@ (2) Assumes ARM CPU mode configured for Little Endian. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + +.global Mem_Copy + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + +.text +.align 2 +.thumb +.syntax unified + +@******************************************************************************************************** +@ Mem_Copy() +@ +@ Description : Copy data octets from one buffer to another buffer. +@ +@ Argument(s) : pdest Pointer to destination memory buffer. +@ +@ psrc Pointer to source memory buffer. +@ +@ size Number of data buffer octets to copy. +@ +@ Return(s) : none. +@ +@ Caller(s) : Application. +@ +@ Note(s) : (1) Null copies allowed (i.e. 0-octet size). +@ +@ (2) Memory buffers NOT checked for overlapping. +@ +@ (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +@ address boundary. +@ +@ (4) ARM Cortex-M3 processors use a subset of the ARM Thumb-2 instruction set which does +@ NOT support 16-bit conditional branch instructions but ONLY supports 8-bit conditional +@ branch instructions. +@ +@ Therefore, branches exceeding 8-bit, signed, relative offsets : +@ +@ (a) CANNOT be implemented with conditional branches@ but ... +@ (b) MUST be implemented with non-conditional branches. +@******************************************************************************************************** + +@ void Mem_Copy (void *pdest, @ ==> R0 +@ void *psrc, @ ==> R1 +@ CPU_SIZE_T size) @ ==> R2 + +.thumb_func +Mem_Copy: + CMP R0, #0 + BNE Mem_Copy_1 + BX LR @ return if pdest == NULL + +Mem_Copy_1: + CMP R1, #0 + BNE Mem_Copy_2 + BX LR @ return if psrc == NULL + +Mem_Copy_2: + CMP R2, #0 + BNE Mem_Copy_3 + BX LR @ return if size == 0 + +Mem_Copy_3: + STMFD SP!, {R3-R12} @ save registers on stack + + +Chk_Align_32: @ check if both dest & src 32-bit aligned + AND R3, R0, #0x03 + AND R4, R1, #0x03 + CMP R3, R4 + BNE Chk_Align_16 @ not 32-bit aligned, check for 16-bit alignment + + RSB R3, R3, #0x04 @ compute 1-2-3 pre-copy bytes (to align to the next 32-bit boundary) + AND R3, R3, #0x03 + +Pre_Copy_1: + CMP R3, #1 @ copy 1-2-3 bytes (to align to the next 32-bit boundary) + BCC Copy_32_1 @ start real 32-bit copy + CMP R2, #1 @ check if any more data to copy + BCS Pre_Copy_1_Cont + B Mem_Copy_END @ no more data to copy (see Note #4b) + +Pre_Copy_1_Cont: + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_1 + + +Chk_Align_16: @ check if both dest & src 16-bit aligned + AND R3, R0, #0x01 + AND R4, R1, #0x01 + CMP R3, R4 + BEQ Pre_Copy_2 + B Copy_08_1 @ not 16-bit aligned, start 8-bit copy (see Note #4b) + +Pre_Copy_2: + CMP R3, #1 @ copy 1 byte (to align to the next 16-bit boundary) + BCC Copy_16_1 @ start real 16-bit copy + + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_2 + + +Copy_32_1: + CMP R2, #360 @ Copy 9 chunks of 10 32-bit words (360 octets per loop) + BCC Copy_32_2 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #360 + B Copy_32_1 + +Copy_32_2: + CMP R2, #(04*10*01) @ Copy chunks of 10 32-bit words (40 octets per loop) + BCC Copy_32_3 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*01) + B Copy_32_2 + +Copy_32_3: + CMP R2, #(04*01*01) @ Copy remaining 32-bit words + BCC Copy_16_1 + LDR R3, [R1], #4 + STR R3, [R0], #4 + SUB R2, R2, #(04*01*01) + B Copy_32_3 + +Copy_16_1: + CMP R2, #(02*01*16) @ Copy chunks of 16 16-bit words (32 bytes per loop) + BCC Copy_16_2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*16) + B Copy_16_1 + +Copy_16_2: + CMP R2, #(02*01*01) @ Copy remaining 16-bit words + BCC Copy_08_1 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*01) + B Copy_16_2 + +Copy_08_1: + CMP R2, #(01*01*16) @ Copy chunks of 16 8-bit words (16 bytes per loop) + BCC Copy_08_2 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*16) + B Copy_08_1 + +Copy_08_2: + CMP R2, #(01*01*01) @ Copy remaining 8-bit words + BCC Mem_Copy_END + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*01) + B Copy_08_2 + + +Mem_Copy_END: + LDMFD SP!, {R3-R12} @ restore registers from stack + BX LR @ return + + +.end + diff --git a/rtos/uC-LIB/Ports/ARM-Cortex-M4/lib_mem_a.s b/rtos/uC-LIB/Ports/ARM-Cortex-M4/lib_mem_a.s new file mode 100644 index 00000000..b213014a --- /dev/null +++ b/rtos/uC-LIB/Ports/ARM-Cortex-M4/lib_mem_a.s @@ -0,0 +1,298 @@ +@******************************************************************************************************** +@ uC/LIB +@ Custom Library Modules +@ +@ Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + + +@******************************************************************************************************** +@ +@ STANDARD MEMORY OPERATIONS +@ +@ ARM-Cortex-M4 +@ GNU Compiler +@ +@ Filename : lib_mem_a.s +@ Version : V1.39.00 +@******************************************************************************************************** +@ Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +@ +@ (a) ALL standard library functions are implemented in the custom library modules : +@ +@ (1) \\lib*.* +@ +@ (2) \\Ports\\\lib*_a.* +@ +@ where +@ directory path for custom library software +@ directory name for specific processor (CPU) +@ directory name for specific compiler +@ +@ (b) Product-specific library functions are implemented in individual products. +@ +@ (2) Assumes ARM CPU mode configured for Little Endian. +@******************************************************************************************************** + + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + +.global Mem_Copy + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + +.text +.align 2 +.thumb +.syntax unified + +@******************************************************************************************************** +@ Mem_Copy() +@ +@ Description : Copy data octets from one buffer to another buffer. +@ +@ Argument(s) : pdest Pointer to destination memory buffer. +@ +@ psrc Pointer to source memory buffer. +@ +@ size Number of data buffer octets to copy. +@ +@ Return(s) : none. +@ +@ Caller(s) : Application. +@ +@ Note(s) : (1) Null copies allowed (i.e. 0-octet size). +@ +@ (2) Memory buffers NOT checked for overlapping. +@ +@ (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +@ address boundary. +@ +@ (4) ARM Cortex-M3 processors use a subset of the ARM Thumb-2 instruction set which does +@ NOT support 16-bit conditional branch instructions but ONLY supports 8-bit conditional +@ branch instructions. +@ +@ Therefore, branches exceeding 8-bit, signed, relative offsets : +@ +@ (a) CANNOT be implemented with conditional branches@ but ... +@ (b) MUST be implemented with non-conditional branches. +@******************************************************************************************************** + +@ void Mem_Copy (void *pdest, @ ==> R0 +@ void *psrc, @ ==> R1 +@ CPU_SIZE_T size) @ ==> R2 + +.thumb_func +Mem_Copy: + CMP R0, #0 + BNE Mem_Copy_1 + BX LR @ return if pdest == NULL + +Mem_Copy_1: + CMP R1, #0 + BNE Mem_Copy_2 + BX LR @ return if psrc == NULL + +Mem_Copy_2: + CMP R2, #0 + BNE Mem_Copy_3 + BX LR @ return if size == 0 + +Mem_Copy_3: + STMFD SP!, {R3-R12} @ save registers on stack + + +Chk_Align_32: @ check if both dest & src 32-bit aligned + AND R3, R0, #0x03 + AND R4, R1, #0x03 + CMP R3, R4 + BNE Chk_Align_16 @ not 32-bit aligned, check for 16-bit alignment + + RSB R3, R3, #0x04 @ compute 1-2-3 pre-copy bytes (to align to the next 32-bit boundary) + AND R3, R3, #0x03 + +Pre_Copy_1: + CMP R3, #1 @ copy 1-2-3 bytes (to align to the next 32-bit boundary) + BCC Copy_32_1 @ start real 32-bit copy + CMP R2, #1 @ check if any more data to copy + BCS Pre_Copy_1_Cont + B Mem_Copy_END @ no more data to copy (see Note #4b) + +Pre_Copy_1_Cont: + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_1 + + +Chk_Align_16: @ check if both dest & src 16-bit aligned + AND R3, R0, #0x01 + AND R4, R1, #0x01 + CMP R3, R4 + BEQ Pre_Copy_2 + B Copy_08_1 @ not 16-bit aligned, start 8-bit copy (see Note #4b) + +Pre_Copy_2: + CMP R3, #1 @ copy 1 byte (to align to the next 16-bit boundary) + BCC Copy_16_1 @ start real 16-bit copy + + LDRB R4, [R1], #1 + STRB R4, [R0], #1 + SUB R3, R3, #1 + SUB R2, R2, #1 + B Pre_Copy_2 + + +Copy_32_1: + CMP R2, #360 @ Copy 9 chunks of 10 32-bit words (360 octets per loop) + BCC Copy_32_2 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #360 + B Copy_32_1 + +Copy_32_2: + CMP R2, #(04*10*01) @ Copy chunks of 10 32-bit words (40 octets per loop) + BCC Copy_32_3 + LDMIA R1!, {R3-R12} + STMIA R0!, {R3-R12} + SUB R2, R2, #(04*10*01) + B Copy_32_2 + +Copy_32_3: + CMP R2, #(04*01*01) @ Copy remaining 32-bit words + BCC Copy_16_1 + LDR R3, [R1], #4 + STR R3, [R0], #4 + SUB R2, R2, #(04*01*01) + B Copy_32_3 + +Copy_16_1: + CMP R2, #(02*01*16) @ Copy chunks of 16 16-bit words (32 bytes per loop) + BCC Copy_16_2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*16) + B Copy_16_1 + +Copy_16_2: + CMP R2, #(02*01*01) @ Copy remaining 16-bit words + BCC Copy_08_1 + LDRH R3, [R1], #2 + STRH R3, [R0], #2 + SUB R2, R2, #(02*01*01) + B Copy_16_2 + +Copy_08_1: + CMP R2, #(01*01*16) @ Copy chunks of 16 8-bit words (16 bytes per loop) + BCC Copy_08_2 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*16) + B Copy_08_1 + +Copy_08_2: + CMP R2, #(01*01*01) @ Copy remaining 8-bit words + BCC Mem_Copy_END + LDRB R3, [R1], #1 + STRB R3, [R0], #1 + SUB R2, R2, #(01*01*01) + B Copy_08_2 + + +Mem_Copy_END: + LDMFD SP!, {R3-R12} @ restore registers from stack + BX LR @ return + + +.end + diff --git a/rtos/uC-LIB/lib_ascii.c b/rtos/uC-LIB/lib_ascii.c new file mode 100644 index 00000000..902b7ac5 --- /dev/null +++ b/rtos/uC-LIB/lib_ascii.c @@ -0,0 +1,644 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII CHARACTER OPERATIONS +* +* Filename : lib_ascii.c +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* +* (2) (a) ECMA-6 '7-Bit coded Character Set' (6th edition), which corresponds to the +* 3rd edition of ISO 646, specifies several versions of a 7-bit character set : +* +* (1) THE GENERAL VERSION, which allows characters at 0x23 and 0x24 to be given a +* set alternate form and allows the characters 0x40, 0x5B, 0x5D, 0x60, 0x7B & +* 0x7D to be assigned a "unique graphic character" or to be declared as unused. +* All other characters are explicitly specified. +* +* (2) THE INTERNATIONAL REFERENCE VERSION, which explicitly specifies all characters +* in the 7-bit character set. +* +* (3) NATIONAL & APPLICATION-ORIENTED VERSIONS, which may be derived from the +* standard in specified ways. +* +* (b) The character set represented in this file reproduces the Internation Reference +* Version. This is identical to the 7-bit character set which occupies Unicode +* characters 0x0000 through 0x007F. The character names are taken from v5.0 of the +* Unicode specification, with certain abbreviations so that the resulting #define +* names will not violate ANSI C naming restriction : +* +* (1) For the Latin capital & lowercase letters, the name components 'LETTER_CAPITAL' +* & 'LETTER_SMALL' are replaced by 'UPPER' & 'LOWER', respectively. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_ASCII_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* ASCII_IsAlpha() +* +* Description : Determine whether a character is an alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphabetic character. +* +* DEF_NO, if character is NOT an alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.2.(2) states that "isalpha() returns true only for the +* characters for which isupper() or islower() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlpha (CPU_CHAR c) +{ + CPU_BOOLEAN alpha; + + + alpha = ASCII_IS_ALPHA(c); + + return (alpha); +} + + +/* +********************************************************************************************************* +* ASCII_IsAlphaNum() +* +* Description : Determine whether a character is an alphanumeric character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphanumeric character. +* +* DEF_NO, if character is NOT an alphanumeric character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.1.(2) states that "isalnum() ... tests for any character +* for which isalpha() or isdigit() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlphaNum (CPU_CHAR c) +{ + CPU_BOOLEAN alpha_num; + + + alpha_num = ASCII_IS_ALPHA_NUM(c); + + return (alpha_num); +} + + +/* +********************************************************************************************************* +* ASCII_IsLower() +* +* Description : Determine whether a character is a lowercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a lowercase alphabetic character. +* +* DEF_NO, if character is NOT a lowercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.7.(2) states that "islower() returns true only for +* the lowercase letters". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsLower (CPU_CHAR c) +{ + CPU_BOOLEAN lower; + + + lower = ASCII_IS_LOWER(c); + + return (lower); +} + + +/* +********************************************************************************************************* +* ASCII_IsUpper() +* +* Description : Determine whether a character is an uppercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an uppercase alphabetic character. +* +* DEF_NO, if character is NOT an uppercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.11.(2) states that "isupper() returns true only for +* the uppercase letters". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsUpper (CPU_CHAR c) +{ + CPU_BOOLEAN upper; + + + upper = ASCII_IS_UPPER(c); + + return (upper); +} + + +/* +********************************************************************************************************* +* ASCII_IsDig() +* +* Description : Determine whether a character is a decimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a decimal-digit character. +* +* DEF_NO, if character is NOT a decimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.5.(2) states that "isdigit() ... tests for any +* decimal-digit character". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDig (CPU_CHAR c) +{ + CPU_BOOLEAN dig; + + + dig = ASCII_IS_DIG(c); + + return (dig); +} + + +/* +********************************************************************************************************* +* ASCII_IsDigOct() +* +* Description : Determine whether a character is an octal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an octal-digit character. +* +* DEF_NO, if character is NOT an octal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDigOct (CPU_CHAR c) +{ + CPU_BOOLEAN dig_oct; + + + dig_oct = ASCII_IS_DIG_OCT(c); + + return (dig_oct); +} + + +/* +********************************************************************************************************* +* ASCII_IsDigHex() +* +* Description : Determine whether a character is a hexadecimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a hexadecimal-digit character. +* +* DEF_NO, if character is NOT a hexadecimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.12.(2) states that "isxdigit() ... tests for any +* hexadecimal-digit character". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsDigHex (CPU_CHAR c) +{ + CPU_BOOLEAN dig_hex; + + + dig_hex = ASCII_IS_DIG_HEX(c); + + return (dig_hex); +} + + +/* +********************************************************************************************************* +* ASCII_IsBlank() +* +* Description : Determine whether a character is a standard blank character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a standard blank character. +* +* DEF_NO, if character is NOT a standard blank character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) states that "isblank() returns true only for +* the standard blank characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) defines "the standard blank characters" as +* the "space (' '), and horizontal tab ('\t')". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsBlank (CPU_CHAR c) +{ + CPU_BOOLEAN blank; + + + blank = ASCII_IS_BLANK(c); + + return (blank); +} + + +/* +********************************************************************************************************* +* ASCII_IsSpace() +* +* Description : Determine whether a character is a white-space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a white-space character. +* +* DEF_NO, if character is NOT a white-space character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) states that "isspace() returns true only +* for the standard white-space characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) defines "the standard white-space characters" +* as the "space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), +* horizontal tab ('\t'), and vertical tab ('\v')". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsSpace (CPU_CHAR c) +{ + CPU_BOOLEAN space; + + + space = ASCII_IS_SPACE(c); + + return (space); +} + + +/* +********************************************************************************************************* +* ASCII_IsPrint() +* +* Description : Determine whether a character is a printing character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a printing character. +* +* DEF_NO, if character is NOT a printing character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.8.(2) states that "isprint() ... tests for any +* printing character including space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsPrint (CPU_CHAR c) +{ + CPU_BOOLEAN print; + + + print = ASCII_IS_PRINT(c); + + return (print); +} + + +/* +********************************************************************************************************* +* ASCII_IsGraph() +* +* Description : Determine whether a character is any printing character except a space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a graphic character. +* +* DEF_NO, if character is NOT a graphic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.6.(2) states that "isgraph() ... tests for any +* printing character except space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsGraph (CPU_CHAR c) +{ + CPU_BOOLEAN graph; + + + graph = ASCII_IS_GRAPH(c); + + return (graph); +} + + +/* +********************************************************************************************************* +* ASCII_IsPunct() +* +* Description : Determine whether a character is a punctuation character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a punctuation character. +* +* DEF_NO, if character is NOT a punctuation character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.9.(2) states that "ispunct() returns true for every +* printing character for which neither isspace() nor isalnum() is true". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsPunct (CPU_CHAR c) +{ + CPU_BOOLEAN punct; + + + punct = ASCII_IS_PUNCT(c); + + return (punct); +} + + +/* +********************************************************************************************************* +* ASCII_IsCtrl() +* +* Description : Determine whether a character is a control character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a control character. +* +* DEF_NO, if character is NOT a control character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.4.(2) states that "iscntrl() ... tests for any +* control character". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, ... the control characters are those whose values lie from +* 0 (NUL) through 0x1F (US), and the character 0x7F (DEL)". +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsCtrl (CPU_CHAR c) +{ + CPU_BOOLEAN ctrl; + + + ctrl = ASCII_IS_CTRL(c); + + return (ctrl); +} + + +/* +********************************************************************************************************* +* ASCII_ToLower() +* +* Description : Convert uppercase alphabetic character to its corresponding lowercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Lowercase equivalent of 'c', if character 'c' is an uppercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.1.(2) states that "tolower() ... converts an +* uppercase letter to a corresponding lowercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.1.(3) states that : +* +* (1) (A) "if the argument is a character for which isupper() is true and there are +* one or more corresponding characters ... for which islower() is true," ... +* (B) "tolower() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +CPU_CHAR ASCII_ToLower (CPU_CHAR c) +{ + CPU_CHAR lower; + + + lower = ASCII_TO_LOWER(c); + + return (lower); +} + + +/* +********************************************************************************************************* +* ASCII_ToUpper() +* +* Description : Convert lowercase alphabetic character to its corresponding uppercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Uppercase equivalent of 'c', if character 'c' is a lowercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.2.(2) states that "toupper() ... converts a +* lowercase letter to a corresponding uppercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.2.(3) states that : +* +* (1) (A) "if the argument is a character for which islower() is true and there are +* one or more corresponding characters ... for which isupper() is true," ... +* (B) "toupper() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +CPU_CHAR ASCII_ToUpper (CPU_CHAR c) +{ + CPU_CHAR upper; + + + upper = ASCII_TO_UPPER(c); + + return (upper); +} + + +/* +********************************************************************************************************* +* ASCII_Cmp() +* +* Description : Determine if two characters are identical (case-insensitive). +* +* Argument(s) : c1 First character. +* +* c2 Second character. +* +* Return(s) : DEF_YES, if the characters are identical. +* +* DEF_NO, if the characters are NOT identical. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_Cmp (CPU_CHAR c1, + CPU_CHAR c2) +{ + CPU_CHAR c1_upper; + CPU_CHAR c2_upper; + CPU_BOOLEAN cmp; + + + c1_upper = ASCII_ToUpper(c1); + c2_upper = ASCII_ToUpper(c2); + cmp = (c1_upper == c2_upper) ? (DEF_YES) : (DEF_NO); + + return (cmp); +} + diff --git a/rtos/uC-LIB/lib_ascii.h b/rtos/uC-LIB/lib_ascii.h new file mode 100644 index 00000000..56021027 --- /dev/null +++ b/rtos/uC-LIB/lib_ascii.h @@ -0,0 +1,833 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII CHARACTER OPERATIONS +* +* Filename : lib_ascii.h +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* +* (2) (a) ECMA-6 '7-Bit coded Character Set' (6th edition), which corresponds to the +* 3rd edition of ISO 646, specifies several versions of a 7-bit character set : +* +* (1) THE GENERAL VERSION, which allows characters at 0x23 and 0x24 to be given a +* set alternate form and allows the characters 0x40, 0x5B, 0x5D, 0x60, 0x7B & +* 0x7D to be assigned a "unique graphic character" or to be declared as unused. +* All other characters are explicitly specified. +* +* (2) THE INTERNATIONAL REFERENCE VERSION, which explicitly specifies all characters +* in the 7-bit character set. +* +* (3) NATIONAL & APPLICATION-ORIENTED VERSIONS, which may be derived from the +* standard in specified ways. +* +* (b) The character set represented in this file reproduces the Internation Reference +* Version. This is identical to the 7-bit character set which occupies Unicode +* characters 0x0000 through 0x007F. The character names are taken from v5.0 of the +* Unicode specification, with certain abbreviations so that the resulting #define +* names will not violate ANSI C naming restriction : +* +* (1) For the Latin capital & lowercase letters, the name components 'LETTER_CAPITAL' +* & 'LETTER_SMALL' are replaced by 'UPPER' & 'LOWER', respectively. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This ASCII library header file is protected from multiple pre-processor inclusion through +* use of the ASCII library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_ASCII_MODULE_PRESENT /* See Note #1. */ +#define LIB_ASCII_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_ASCII_MODULE +#define LIB_ASCII_EXT +#else +#define LIB_ASCII_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII CHARACTER DEFINES +********************************************************************************************************* +*/ + + /* -------------------- C0 CONTROLS ------------------- */ +#define ASCII_CHAR_NULL 0x00 /* '\0' */ +#define ASCII_CHAR_START_OF_HEADING 0x01 +#define ASCII_CHAR_START_OF_TEXT 0x02 +#define ASCII_CHAR_END_OF_TEXT 0x03 +#define ASCII_CHAR_END_OF_TRANSMISSION 0x04 +#define ASCII_CHAR_ENQUIRY 0x05 +#define ASCII_CHAR_ACKNOWLEDGE 0x06 +#define ASCII_CHAR_BELL 0x07 /* '\a' */ +#define ASCII_CHAR_BACKSPACE 0x08 /* '\b' */ +#define ASCII_CHAR_CHARACTER_TABULATION 0x09 /* '\t' */ +#define ASCII_CHAR_LINE_FEED 0x0A /* '\n' */ +#define ASCII_CHAR_LINE_TABULATION 0x0B /* '\v' */ +#define ASCII_CHAR_FORM_FEED 0x0C /* '\f' */ +#define ASCII_CHAR_CARRIAGE_RETURN 0x0D /* '\r' */ +#define ASCII_CHAR_SHIFT_OUT 0x0E +#define ASCII_CHAR_SHIFT_IN 0x0F +#define ASCII_CHAR_DATA_LINK_ESCAPE 0x10 +#define ASCII_CHAR_DEVICE_CONTROL_ONE 0x11 +#define ASCII_CHAR_DEVICE_CONTROL_TWO 0x12 +#define ASCII_CHAR_DEVICE_CONTROL_THREE 0x13 +#define ASCII_CHAR_DEVICE_CONTROL_FOUR 0x14 +#define ASCII_CHAR_NEGATIVE_ACKNOWLEDGE 0x15 +#define ASCII_CHAR_SYNCHRONOUS_IDLE 0x16 +#define ASCII_CHAR_END_OF_TRANSMISSION_BLOCK 0x17 +#define ASCII_CHAR_CANCEL 0x18 +#define ASCII_CHAR_END_OF_MEDIUM 0x19 +#define ASCII_CHAR_SUBSITUTE 0x1A +#define ASCII_CHAR_ESCAPE 0x1B +#define ASCII_CHAR_INFO_SEPARATOR_FOUR 0x1C +#define ASCII_CHAR_INFO_SEPARATOR_THREE 0x1D +#define ASCII_CHAR_INFO_SEPARATOR_TWO 0x1E +#define ASCII_CHAR_INFO_SEPARATOR_ONE 0x1F + +#define ASCII_CHAR_NUL ASCII_CHAR_NULL +#define ASCII_CHAR_SOH ASCII_CHAR_START_OF_HEADING +#define ASCII_CHAR_START_HEADING ASCII_CHAR_START_OF_HEADING +#define ASCII_CHAR_STX ASCII_CHAR_START_OF_TEXT +#define ASCII_CHAR_START_TEXT ASCII_CHAR_START_OF_TEXT +#define ASCII_CHAR_ETX ASCII_CHAR_END_OF_TEXT +#define ASCII_CHAR_END_TEXT ASCII_CHAR_END_OF_TEXT +#define ASCII_CHAR_EOT ASCII_CHAR_END_OF_TRANSMISSION +#define ASCII_CHAR_END_TRANSMISSION ASCII_CHAR_END_OF_TRANSMISSION +#define ASCII_CHAR_ENQ ASCII_CHAR_ENQUIRY +#define ASCII_CHAR_ACK ASCII_CHAR_ACKNOWLEDGE +#define ASCII_CHAR_BEL ASCII_CHAR_BELL +#define ASCII_CHAR_BS ASCII_CHAR_BACKSPACE +#define ASCII_CHAR_HT ASCII_CHAR_CHARACTER_TABULATION +#define ASCII_CHAR_TAB ASCII_CHAR_CHARACTER_TABULATION +#define ASCII_CHAR_LF ASCII_CHAR_LINE_FEED +#define ASCII_CHAR_VT ASCII_CHAR_LINE_TABULATION +#define ASCII_CHAR_FF ASCII_CHAR_FORM_FEED +#define ASCII_CHAR_CR ASCII_CHAR_CARRIAGE_RETURN +#define ASCII_CHAR_SO ASCII_CHAR_SHIFT_OUT +#define ASCII_CHAR_SI ASCII_CHAR_SHIFT_IN +#define ASCII_CHAR_DLE ASCII_CHAR_DATA_LINK_ESCAPE +#define ASCII_CHAR_DC1 ASCII_CHAR_DEVICE_CONTROL_ONE +#define ASCII_CHAR_DC2 ASCII_CHAR_DEVICE_CONTROL_TWO +#define ASCII_CHAR_DC3 ASCII_CHAR_DEVICE_CONTROL_THREE +#define ASCII_CHAR_DC4 ASCII_CHAR_DEVICE_CONTROL_FOUR +#define ASCII_CHAR_DEV_CTRL_ONE ASCII_CHAR_DEVICE_CONTROL_ONE +#define ASCII_CHAR_DEV_CTRL_TWO ASCII_CHAR_DEVICE_CONTROL_TWO +#define ASCII_CHAR_DEV_CTRL_THREE ASCII_CHAR_DEVICE_CONTROL_THREE +#define ASCII_CHAR_DEV_CTRL_FOUR ASCII_CHAR_DEVICE_CONTROL_FOUR +#define ASCII_CHAR_NAK ASCII_CHAR_NEGATIVE_ACKNOWLEDGE +#define ASCII_CHAR_NEG_ACK ASCII_CHAR_NEGATIVE_ACKNOWLEDGE +#define ASCII_CHAR_SYN ASCII_CHAR_SYNCHRONOUS_IDLE +#define ASCII_CHAR_SYNC_IDLE ASCII_CHAR_SYNCHRONOUS_IDLE +#define ASCII_CHAR_ETB ASCII_CHAR_END_OF_TRANSMISSION_BLOCK +#define ASCII_CHAR_END_TRANSMISSION_BLK ASCII_CHAR_END_OF_TRANSMISSION_BLOCK +#define ASCII_CHAR_CAN ASCII_CHAR_CANCEL +#define ASCII_CHAR_EM ASCII_CHAR_END_OF_MEDIUM +#define ASCII_CHAR_END_MEDIUM ASCII_CHAR_END_OF_MEDIUM +#define ASCII_CHAR_SUB ASCII_CHAR_SUBSITUTE +#define ASCII_CHAR_ESC ASCII_CHAR_ESCAPE +#define ASCII_CHAR_IS1 ASCII_CHAR_INFO_SEPARATOR_ONE +#define ASCII_CHAR_IS2 ASCII_CHAR_INFO_SEPARATOR_TWO +#define ASCII_CHAR_IS3 ASCII_CHAR_INFO_SEPARATOR_THREE +#define ASCII_CHAR_IS4 ASCII_CHAR_INFO_SEPARATOR_FOUR + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_SPACE 0x20 /* ' ' */ +#define ASCII_CHAR_EXCLAMATION_MARK 0x21 /* '!' */ +#define ASCII_CHAR_QUOTATION_MARK 0x22 /* '\"' */ +#define ASCII_CHAR_NUMBER_SIGN 0x23 /* '#' */ +#define ASCII_CHAR_DOLLAR_SIGN 0x24 /* '$' */ +#define ASCII_CHAR_PERCENTAGE_SIGN 0x25 /* '%' */ +#define ASCII_CHAR_AMPERSAND 0x26 /* '&' */ +#define ASCII_CHAR_APOSTROPHE 0x27 /* '\'' */ +#define ASCII_CHAR_LEFT_PARENTHESIS 0x28 /* '(' */ +#define ASCII_CHAR_RIGHT_PARENTHESIS 0x29 /* ')' */ +#define ASCII_CHAR_ASTERISK 0x2A /* '*' */ +#define ASCII_CHAR_PLUS_SIGN 0x2B /* '+' */ +#define ASCII_CHAR_COMMA 0x2C /* ',' */ +#define ASCII_CHAR_HYPHEN_MINUS 0x2D /* '-' */ +#define ASCII_CHAR_FULL_STOP 0x2E /* '.' */ +#define ASCII_CHAR_SOLIDUS 0x2F /* '/' */ + +#define ASCII_CHAR_PAREN_LEFT ASCII_CHAR_LEFT_PARENTHESIS +#define ASCII_CHAR_PAREN_RIGHT ASCII_CHAR_RIGHT_PARENTHESIS + + + /* ------------------- ASCII DIGITS ------------------- */ +#define ASCII_CHAR_DIGIT_ZERO 0x30 /* '0' */ +#define ASCII_CHAR_DIGIT_ONE 0x31 /* '1' */ +#define ASCII_CHAR_DIGIT_TWO 0x32 /* '2' */ +#define ASCII_CHAR_DIGIT_THREE 0x33 /* '3' */ +#define ASCII_CHAR_DIGIT_FOUR 0x34 /* '4' */ +#define ASCII_CHAR_DIGIT_FIVE 0x35 /* '5' */ +#define ASCII_CHAR_DIGIT_SIX 0x36 /* '6' */ +#define ASCII_CHAR_DIGIT_SEVEN 0x37 /* '7' */ +#define ASCII_CHAR_DIGIT_EIGHT 0x38 /* '8' */ +#define ASCII_CHAR_DIGIT_NINE 0x39 /* '9' */ + +#define ASCII_CHAR_DIG_ZERO ASCII_CHAR_DIGIT_ZERO +#define ASCII_CHAR_DIG_ONE ASCII_CHAR_DIGIT_ONE +#define ASCII_CHAR_DIG_TWO ASCII_CHAR_DIGIT_TWO +#define ASCII_CHAR_DIG_THREE ASCII_CHAR_DIGIT_THREE +#define ASCII_CHAR_DIG_FOUR ASCII_CHAR_DIGIT_FOUR +#define ASCII_CHAR_DIG_FIVE ASCII_CHAR_DIGIT_FIVE +#define ASCII_CHAR_DIG_SIX ASCII_CHAR_DIGIT_SIX +#define ASCII_CHAR_DIG_SEVEN ASCII_CHAR_DIGIT_SEVEN +#define ASCII_CHAR_DIG_EIGHT ASCII_CHAR_DIGIT_EIGHT +#define ASCII_CHAR_DIG_NINE ASCII_CHAR_DIGIT_NINE + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_COLON 0x3A /* ':' */ +#define ASCII_CHAR_SEMICOLON 0x3B /* ';' */ +#define ASCII_CHAR_LESS_THAN_SIGN 0x3C /* '<' */ +#define ASCII_CHAR_EQUALS_SIGN 0x3D /* '=' */ +#define ASCII_CHAR_GREATER_THAN_SIGN 0x3E /* '>' */ +#define ASCII_CHAR_QUESTION_MARK 0x3F /* '\?' */ +#define ASCII_CHAR_COMMERCIAL_AT 0x40 /* '@' */ + +#define ASCII_CHAR_AT_SIGN ASCII_CHAR_COMMERCIAL_AT + + + /* ------------- UPPERCASE LATIN ALPHABET ------------- */ +#define ASCII_CHAR_LATIN_UPPER_A 0x41 /* 'A' */ +#define ASCII_CHAR_LATIN_UPPER_B 0x42 /* 'B' */ +#define ASCII_CHAR_LATIN_UPPER_C 0x43 /* 'C' */ +#define ASCII_CHAR_LATIN_UPPER_D 0x44 /* 'D' */ +#define ASCII_CHAR_LATIN_UPPER_E 0x45 /* 'E' */ +#define ASCII_CHAR_LATIN_UPPER_F 0x46 /* 'F' */ +#define ASCII_CHAR_LATIN_UPPER_G 0x47 /* 'G' */ +#define ASCII_CHAR_LATIN_UPPER_H 0x48 /* 'H' */ +#define ASCII_CHAR_LATIN_UPPER_I 0x49 /* 'I' */ +#define ASCII_CHAR_LATIN_UPPER_J 0x4A /* 'J' */ +#define ASCII_CHAR_LATIN_UPPER_K 0x4B /* 'K' */ +#define ASCII_CHAR_LATIN_UPPER_L 0x4C /* 'L' */ +#define ASCII_CHAR_LATIN_UPPER_M 0x4D /* 'M' */ +#define ASCII_CHAR_LATIN_UPPER_N 0x4E /* 'N' */ +#define ASCII_CHAR_LATIN_UPPER_O 0x4F /* 'O' */ +#define ASCII_CHAR_LATIN_UPPER_P 0x50 /* 'P' */ +#define ASCII_CHAR_LATIN_UPPER_Q 0x51 /* 'Q' */ +#define ASCII_CHAR_LATIN_UPPER_R 0x52 /* 'R' */ +#define ASCII_CHAR_LATIN_UPPER_S 0x53 /* 'S' */ +#define ASCII_CHAR_LATIN_UPPER_T 0x54 /* 'T' */ +#define ASCII_CHAR_LATIN_UPPER_U 0x55 /* 'U' */ +#define ASCII_CHAR_LATIN_UPPER_V 0x56 /* 'V' */ +#define ASCII_CHAR_LATIN_UPPER_W 0x57 /* 'W' */ +#define ASCII_CHAR_LATIN_UPPER_X 0x58 /* 'X' */ +#define ASCII_CHAR_LATIN_UPPER_Y 0x59 /* 'Y' */ +#define ASCII_CHAR_LATIN_UPPER_Z 0x5A /* 'Z' */ + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_LEFT_SQUARE_BRACKET 0x5B /* '[' */ +#define ASCII_CHAR_REVERSE_SOLIDUS 0x5C /* '\\' */ +#define ASCII_CHAR_RIGHT_SQUARE_BRACKET 0x5D /* ']' */ +#define ASCII_CHAR_CIRCUMFLEX_ACCENT 0x5E /* '^' */ +#define ASCII_CHAR_LOW_LINE 0x5F /* '_' */ +#define ASCII_CHAR_GRAVE_ACCENT 0x60 /* '`' */ + +#define ASCII_CHAR_BRACKET_SQUARE_LEFT ASCII_CHAR_LEFT_SQUARE_BRACKET +#define ASCII_CHAR_BRACKET_SQUARE_RIGHT ASCII_CHAR_RIGHT_SQUARE_BRACKET + + + /* ------------- LOWERCASE LATIN ALPHABET ------------- */ +#define ASCII_CHAR_LATIN_LOWER_A 0x61 /* 'a' */ +#define ASCII_CHAR_LATIN_LOWER_B 0x62 /* 'b' */ +#define ASCII_CHAR_LATIN_LOWER_C 0x63 /* 'c' */ +#define ASCII_CHAR_LATIN_LOWER_D 0x64 /* 'd' */ +#define ASCII_CHAR_LATIN_LOWER_E 0x65 /* 'e' */ +#define ASCII_CHAR_LATIN_LOWER_F 0x66 /* 'f' */ +#define ASCII_CHAR_LATIN_LOWER_G 0x67 /* 'g' */ +#define ASCII_CHAR_LATIN_LOWER_H 0x68 /* 'h' */ +#define ASCII_CHAR_LATIN_LOWER_I 0x69 /* 'i' */ +#define ASCII_CHAR_LATIN_LOWER_J 0x6A /* 'j' */ +#define ASCII_CHAR_LATIN_LOWER_K 0x6B /* 'k' */ +#define ASCII_CHAR_LATIN_LOWER_L 0x6C /* 'l' */ +#define ASCII_CHAR_LATIN_LOWER_M 0x6D /* 'm' */ +#define ASCII_CHAR_LATIN_LOWER_N 0x6E /* 'n' */ +#define ASCII_CHAR_LATIN_LOWER_O 0x6F /* 'o' */ +#define ASCII_CHAR_LATIN_LOWER_P 0x70 /* 'p' */ +#define ASCII_CHAR_LATIN_LOWER_Q 0x71 /* 'q' */ +#define ASCII_CHAR_LATIN_LOWER_R 0x72 /* 'r' */ +#define ASCII_CHAR_LATIN_LOWER_S 0x73 /* 's' */ +#define ASCII_CHAR_LATIN_LOWER_T 0x74 /* 't' */ +#define ASCII_CHAR_LATIN_LOWER_U 0x75 /* 'u' */ +#define ASCII_CHAR_LATIN_LOWER_V 0x76 /* 'v' */ +#define ASCII_CHAR_LATIN_LOWER_W 0x77 /* 'w' */ +#define ASCII_CHAR_LATIN_LOWER_X 0x78 /* 'x' */ +#define ASCII_CHAR_LATIN_LOWER_Y 0x79 /* 'y' */ +#define ASCII_CHAR_LATIN_LOWER_Z 0x7A /* 'z' */ + + + /* ------------ ASCII PUNCTUATION & SYMBOLS ----------- */ +#define ASCII_CHAR_LEFT_CURLY_BRACKET 0x7B /* '{' */ +#define ASCII_CHAR_VERTICAL_LINE 0x7C /* '|' */ +#define ASCII_CHAR_RIGHT_CURLY_BRACKET 0x7D /* '}' */ +#define ASCII_CHAR_TILDE 0x7E /* '~' */ + +#define ASCII_CHAR_BRACKET_CURLY_LEFT ASCII_CHAR_LEFT_CURLY_BRACKET +#define ASCII_CHAR_BRACKET_CURLY_RIGHT ASCII_CHAR_RIGHT_CURLY_BRACKET + + + /* ---------------- CONTROL CHARACTERS ---------------- */ +#define ASCII_CHAR_DELETE 0x7F + +#define ASCII_CHAR_DEL ASCII_CHAR_DELETE + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII CHARACTER CLASSIFICATION MACRO's +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.(1) states that "character classification functions ... +* return nonzero (true) if and only if the value of the argument 'c' conforms to ... the +* description of the function." +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII_IS_DIG() +* +* Description : Determine whether a character is a decimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a decimal-digit character. +* +* DEF_NO, if character is NOT a decimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.5.(2) states that "isdigit() ... tests for any +* decimal-digit character". +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG(c) ((((c) >= ASCII_CHAR_DIG_ZERO) && ((c) <= ASCII_CHAR_DIG_NINE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_DIG_OCT() +* +* Description : Determine whether a character is an octal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an octal-digit character. +* +* DEF_NO, if character is NOT an octal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG_OCT(c) ((((c) >= ASCII_CHAR_DIG_ZERO) && ((c) <= ASCII_CHAR_DIG_SEVEN)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_DIG_HEX() +* +* Description : Determine whether a character is a hexadecimal-digit character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a hexadecimal-digit character. +* +* DEF_NO, if character is NOT a hexadecimal-digit character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.12.(2) states that "isxdigit() ... tests for any +* hexadecimal-digit character". +********************************************************************************************************* +*/ + +#define ASCII_IS_DIG_HEX(c) (((((c) >= ASCII_CHAR_DIG_ZERO ) && ((c) <= ASCII_CHAR_DIG_NINE )) || \ + (((c) >= ASCII_CHAR_LATIN_UPPER_A) && ((c) <= ASCII_CHAR_LATIN_UPPER_F)) || \ + (((c) >= ASCII_CHAR_LATIN_LOWER_A) && ((c) <= ASCII_CHAR_LATIN_LOWER_F))) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_LOWER() +* +* Description : Determine whether a character is a lowercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a lowercase alphabetic character. +* +* DEF_NO, if character is NOT a lowercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.7.(2) states that "islower() returns true only for +* the lowercase letters". +********************************************************************************************************* +*/ + +#define ASCII_IS_LOWER(c) ((((c) >= ASCII_CHAR_LATIN_LOWER_A) && ((c) <= ASCII_CHAR_LATIN_LOWER_Z)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_UPPER() +* +* Description : Determine whether a character is an uppercase alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an uppercase alphabetic character. +* +* DEF_NO, if character is NOT an uppercase alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.11.(2) states that "isupper() returns true only for +* the uppercase letters". +********************************************************************************************************* +*/ + +#define ASCII_IS_UPPER(c) ((((c) >= ASCII_CHAR_LATIN_UPPER_A) && ((c) <= ASCII_CHAR_LATIN_UPPER_Z)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_ALPHA() +* +* Description : Determine whether a character is an alphabetic character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphabetic character. +* +* DEF_NO, if character is NOT an alphabetic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.2.(2) states that "isalpha() returns true only for the +* characters for which isupper() or islower() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_ALPHA(c) ((((ASCII_IS_UPPER(c)) == DEF_YES) || \ + ((ASCII_IS_LOWER(c)) == DEF_YES)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_ALPHA_NUM() +* +* Description : Determine whether a character is an alphanumeric character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is an alphanumeric character. +* +* DEF_NO, if character is NOT an alphanumeric character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.1.(2) states that "isalnum() ... tests for any character +* for which isalpha() or isdigit() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_ALPHA_NUM(c) ((((ASCII_IS_ALPHA(c)) == DEF_YES) || \ + ((ASCII_IS_DIG (c)) == DEF_YES)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_BLANK() +* +* Description : Determine whether a character is a standard blank character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a standard blank character. +* +* DEF_NO, if character is NOT a standard blank character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) states that "isblank() returns true only for +* the standard blank characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.3.(2) defines "the standard blank characters" as +* the "space (' '), and horizontal tab ('\t')". +********************************************************************************************************* +*/ + +#define ASCII_IS_BLANK(c) ((((c) == ASCII_CHAR_SPACE) || ((c) == ASCII_CHAR_HT)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_SPACE() +* +* Description : Determine whether a character is a white-space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a white-space character. +* +* DEF_NO, if character is NOT a white-space character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) states that "isspace() returns true only +* for the standard white-space characters". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.1.10.(2) defines "the standard white-space characters" +* as the "space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), +* horizontal tab ('\t'), and vertical tab ('\v')". +********************************************************************************************************* +*/ + +#define ASCII_IS_SPACE(c) ((((c) == ASCII_CHAR_SPACE) || ((c) == ASCII_CHAR_CR) || \ + ((c) == ASCII_CHAR_LF ) || ((c) == ASCII_CHAR_FF) || \ + ((c) == ASCII_CHAR_HT ) || ((c) == ASCII_CHAR_VT)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_PRINT() +* +* Description : Determine whether a character is a printing character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a printing character. +* +* DEF_NO, if character is NOT a printing character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.8.(2) states that "isprint() ... tests for any +* printing character including space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +#define ASCII_IS_PRINT(c) ((((c) >= ASCII_CHAR_SPACE) && ((c) <= ASCII_CHAR_TILDE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_GRAPH() +* +* Description : Determine whether a character is any printing character except a space character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a graphic character. +* +* DEF_NO, if character is NOT a graphic character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.6.(2) states that "isgraph() ... tests for any +* printing character except space (' ')". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, the printing characters are those whose values lie from +* 0x20 (space) through 0x7E (tilde)". +********************************************************************************************************* +*/ + +#define ASCII_IS_GRAPH(c) ((((c) >= ASCII_CHAR_EXCLAMATION_MARK) && ((c) <= ASCII_CHAR_TILDE)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_PUNCT() +* +* Description : Determine whether a character is a punctuation character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a punctuation character. +* +* DEF_NO, if character is NOT a punctuation character. +* +* Caller(s) : Application. +* +* Note(s) : (1) ISO/IEC 9899:TC2, Section 7.4.1.9.(2) states that "ispunct() returns true for every +* printing character for which neither isspace() nor isalnum() is true". +********************************************************************************************************* +*/ + +#define ASCII_IS_PUNCT(c) (((((c) > ASCII_CHAR_SPACE) && ((c) < ASCII_CHAR_DIGIT_ZERO)) || \ + (((c) > ASCII_CHAR_DIGIT_NINE) && ((c) < ASCII_CHAR_LATIN_UPPER_A)) || \ + (((c) > ASCII_CHAR_LATIN_UPPER_Z) && ((c) < ASCII_CHAR_LATIN_LOWER_A)) || \ + (((c) > ASCII_CHAR_LATIN_LOWER_Z) && ((c) < ASCII_CHAR_DELETE))) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII_IS_CTRL() +* +* Description : Determine whether a character is a control character. +* +* Argument(s) : c Character to examine. +* +* Return(s) : DEF_YES, if character is a control character. +* +* DEF_NO, if character is NOT a control character. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.1.4.(2) states that "iscntrl() ... tests for any +* control character". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.(3), Note 169, states that in "the seven-bit US +* ASCII character set, ... the control characters are those whose values lie from +* 0 (NUL) through 0x1F (US), and the character 0x7F (DEL)". +********************************************************************************************************* +*/ + +#define ASCII_IS_CTRL(c) (((((CPU_INT08S)(c) >= ASCII_CHAR_NULL ) && ((c) <= ASCII_CHAR_IS1)) || \ + ((c) == ASCII_CHAR_DEL)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* ASCII CHARACTER CASE MAPPING MACRO's +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* ASCII_TO_LOWER() +* +* Description : Convert uppercase alphabetic character to its corresponding lowercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Lowercase equivalent of 'c', if character 'c' is an uppercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.1.(2) states that "tolower() ... converts an +* uppercase letter to a corresponding lowercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.1.(3) states that : +* +* (1) (A) "if the argument is a character for which isupper() is true and there are +* one or more corresponding characters ... for which islower() is true," ... +* (B) "tolower() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +#define ASCII_TO_LOWER(c) (((ASCII_IS_UPPER(c)) == DEF_YES) ? ((c) + (ASCII_CHAR_LATIN_LOWER_A - ASCII_CHAR_LATIN_UPPER_A)) : (c)) + + +/* +********************************************************************************************************* +* ASCII_TO_UPPER() +* +* Description : Convert lowercase alphabetic character to its corresponding uppercase alphabetic character. +* +* Argument(s) : c Character to convert. +* +* Return(s) : Uppercase equivalent of 'c', if character 'c' is a lowercase character (see Note #1b1). +* +* Character 'c', otherwise (see Note #1b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) ISO/IEC 9899:TC2, Section 7.4.2.2.(2) states that "toupper() ... converts a +* lowercase letter to a corresponding uppercase letter". +* +* (b) ISO/IEC 9899:TC2, Section 7.4.2.2.(3) states that : +* +* (1) (A) "if the argument is a character for which islower() is true and there are +* one or more corresponding characters ... for which isupper() is true," ... +* (B) "toupper() ... returns one of the corresponding characters;" ... +* +* (2) "otherwise, the argument is returned unchanged." +********************************************************************************************************* +*/ + +#define ASCII_TO_UPPER(c) (((ASCII_IS_LOWER(c)) == DEF_YES) ? ((c) - (ASCII_CHAR_LATIN_LOWER_A - ASCII_CHAR_LATIN_UPPER_A)) : (c)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +CPU_BOOLEAN ASCII_IsAlpha (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsAlphaNum(CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsLower (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsUpper (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDig (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDigOct (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsDigHex (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsBlank (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsSpace (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsPrint (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsGraph (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsPunct (CPU_CHAR c); + +CPU_BOOLEAN ASCII_IsCtrl (CPU_CHAR c); + + +CPU_CHAR ASCII_ToLower (CPU_CHAR c); + +CPU_CHAR ASCII_ToUpper (CPU_CHAR c); + + +CPU_BOOLEAN ASCII_Cmp (CPU_CHAR c1, + CPU_CHAR c2); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_ascii.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib ascii module include. */ + diff --git a/rtos/uC-LIB/lib_def.h b/rtos/uC-LIB/lib_def.h new file mode 100644 index 00000000..541395a6 --- /dev/null +++ b/rtos/uC-LIB/lib_def.h @@ -0,0 +1,1360 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CORE CUSTOM LIBRARY MODULE +* +* Filename : lib_def.h +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/CPU V1.29.00 +* +* +* (2) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This library definition header file is protected from multiple pre-processor inclusion +* through use of the library definition module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_DEF_MODULE_PRESENT +#define LIB_DEF_MODULE_PRESENT + + +/* +********************************************************************************************************* +* CUSTOM LIBRARY MODULE VERSION NUMBER +* +* Note(s) : (1) (a) The custom library module software version is denoted as follows : +* +* Vx.yy.zz +* +* where +* V denotes 'Version' label +* x denotes major software version revision number +* yy denotes minor software version revision number +* zz denotes sub-minor software version revision number +* +* (b) The software version label #define is formatted as follows : +* +* ver = x.yyzz * 100 * 100 +* +* where +* ver denotes software version number scaled as an integer value +* x.yyzz denotes software version number, where the unscaled integer +* portion denotes the major version number & the unscaled +* fractional portion denotes the (concatenated) minor +* version numbers +********************************************************************************************************* +*/ + +#define LIB_VERSION 13900u /* See Note #1. */ + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +********************************************************************************************************* +*/ + +#include +#include + + +/* +********************************************************************************************************* +* STANDARD DEFINES +********************************************************************************************************* +*/ + +#define DEF_NULL 0 + + + /* ----------------- BOOLEAN DEFINES ------------------ */ +#define DEF_FALSE 0u +#define DEF_TRUE 1u + +#define DEF_NO 0u +#define DEF_YES 1u + +#define DEF_DISABLED 0u +#define DEF_ENABLED 1u + +#define DEF_INACTIVE 0u +#define DEF_ACTIVE 1u + +#define DEF_INVALID 0u +#define DEF_VALID 1u + +#define DEF_OFF 0u +#define DEF_ON 1u + +#define DEF_CLR 0u +#define DEF_SET 1u + +#define DEF_FAIL 0u +#define DEF_OK 1u + + + /* ------------------- BIT DEFINES -------------------- */ +#define DEF_BIT_NONE 0x00u + +#define DEF_BIT_00 0x01u +#define DEF_BIT_01 0x02u +#define DEF_BIT_02 0x04u +#define DEF_BIT_03 0x08u +#define DEF_BIT_04 0x10u +#define DEF_BIT_05 0x20u +#define DEF_BIT_06 0x40u +#define DEF_BIT_07 0x80u + +#define DEF_BIT_08 0x0100u +#define DEF_BIT_09 0x0200u +#define DEF_BIT_10 0x0400u +#define DEF_BIT_11 0x0800u +#define DEF_BIT_12 0x1000u +#define DEF_BIT_13 0x2000u +#define DEF_BIT_14 0x4000u +#define DEF_BIT_15 0x8000u + +#define DEF_BIT_16 0x00010000u +#define DEF_BIT_17 0x00020000u +#define DEF_BIT_18 0x00040000u +#define DEF_BIT_19 0x00080000u +#define DEF_BIT_20 0x00100000u +#define DEF_BIT_21 0x00200000u +#define DEF_BIT_22 0x00400000u +#define DEF_BIT_23 0x00800000u + +#define DEF_BIT_24 0x01000000u +#define DEF_BIT_25 0x02000000u +#define DEF_BIT_26 0x04000000u +#define DEF_BIT_27 0x08000000u +#define DEF_BIT_28 0x10000000u +#define DEF_BIT_29 0x20000000u +#define DEF_BIT_30 0x40000000u +#define DEF_BIT_31 0x80000000u +#define DEF_BIT_32 0x0000000100000000u +#define DEF_BIT_33 0x0000000200000000u +#define DEF_BIT_34 0x0000000400000000u +#define DEF_BIT_35 0x0000000800000000u +#define DEF_BIT_36 0x0000001000000000u +#define DEF_BIT_37 0x0000002000000000u +#define DEF_BIT_38 0x0000004000000000u +#define DEF_BIT_39 0x0000008000000000u + +#define DEF_BIT_40 0x0000010000000000u +#define DEF_BIT_41 0x0000020000000000u +#define DEF_BIT_42 0x0000040000000000u +#define DEF_BIT_43 0x0000080000000000u +#define DEF_BIT_44 0x0000100000000000u +#define DEF_BIT_45 0x0000200000000000u +#define DEF_BIT_46 0x0000400000000000u +#define DEF_BIT_47 0x0000800000000000u + +#define DEF_BIT_48 0x0001000000000000u +#define DEF_BIT_49 0x0002000000000000u +#define DEF_BIT_50 0x0004000000000000u +#define DEF_BIT_51 0x0008000000000000u +#define DEF_BIT_52 0x0010000000000000u +#define DEF_BIT_53 0x0020000000000000u +#define DEF_BIT_54 0x0040000000000000u +#define DEF_BIT_55 0x0080000000000000u + +#define DEF_BIT_56 0x0100000000000000u +#define DEF_BIT_57 0x0200000000000000u +#define DEF_BIT_58 0x0400000000000000u +#define DEF_BIT_59 0x0800000000000000u +#define DEF_BIT_60 0x1000000000000000u +#define DEF_BIT_61 0x2000000000000000u +#define DEF_BIT_62 0x4000000000000000u +#define DEF_BIT_63 0x8000000000000000u + + + /* ------------------ ALIGN DEFINES ------------------- */ +#define DEF_ALIGN_MAX_NBR_OCTETS 4096u + + + /* ------------------ OCTET DEFINES ------------------- */ +#define DEF_OCTET_NBR_BITS 8u +#define DEF_OCTET_MASK 0xFFu + +#define DEF_OCTET_TO_BIT_NBR_BITS 3u +#define DEF_OCTET_TO_BIT_SHIFT DEF_OCTET_TO_BIT_NBR_BITS +#define DEF_OCTET_TO_BIT_MASK 0x07u + + +#define DEF_NIBBLE_NBR_BITS 4u +#define DEF_NIBBLE_MASK 0x0Fu + + + /* --------------- NUMBER BASE DEFINES ---------------- */ +#define DEF_NBR_BASE_BIN 2u +#define DEF_NBR_BASE_OCT 8u +#define DEF_NBR_BASE_DEC 10u +#define DEF_NBR_BASE_HEX 16u + + + /* ----------------- INTEGER DEFINES ------------------ */ +#define DEF_INT_08_NBR_BITS 8u +#define DEF_INT_08_MASK 0xFFu + +#define DEF_INT_08U_MIN_VAL 0u +#define DEF_INT_08U_MAX_VAL 255u + +#define DEF_INT_08S_MIN_VAL_ONES_CPL (-127) +#define DEF_INT_08S_MAX_VAL_ONES_CPL 127 + +#define DEF_INT_08S_MIN_VAL (DEF_INT_08S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_08S_MAX_VAL DEF_INT_08S_MAX_VAL_ONES_CPL + +#define DEF_INT_08U_NBR_DIG_MIN 1u +#define DEF_INT_08U_NBR_DIG_MAX 3u + +#define DEF_INT_08S_NBR_DIG_MIN 3u +#define DEF_INT_08S_NBR_DIG_MAX 3u + + + +#define DEF_INT_16_NBR_BITS 16u +#define DEF_INT_16_MASK 0xFFFFu + +#define DEF_INT_16U_MIN_VAL 0u +#define DEF_INT_16U_MAX_VAL 65535u + +#define DEF_INT_16S_MIN_VAL_ONES_CPL (-32767) +#define DEF_INT_16S_MAX_VAL_ONES_CPL 32767 + +#define DEF_INT_16S_MIN_VAL (DEF_INT_16S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_16S_MAX_VAL DEF_INT_16S_MAX_VAL_ONES_CPL + +#define DEF_INT_16U_NBR_DIG_MIN 1u +#define DEF_INT_16U_NBR_DIG_MAX 5u + +#define DEF_INT_16S_NBR_DIG_MIN 5u +#define DEF_INT_16S_NBR_DIG_MAX 5u + + + +#define DEF_INT_32_NBR_BITS 32u +#define DEF_INT_32_MASK 0xFFFFFFFFu + +#define DEF_INT_32U_MIN_VAL 0u +#define DEF_INT_32U_MAX_VAL 4294967295u + +#define DEF_INT_32S_MIN_VAL_ONES_CPL (-2147483647) +#define DEF_INT_32S_MAX_VAL_ONES_CPL 2147483647 + +#define DEF_INT_32S_MIN_VAL (DEF_INT_32S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_32S_MAX_VAL DEF_INT_32S_MAX_VAL_ONES_CPL + +#define DEF_INT_32U_NBR_DIG_MIN 1u +#define DEF_INT_32U_NBR_DIG_MAX 10u + +#define DEF_INT_32S_NBR_DIG_MIN 10u +#define DEF_INT_32S_NBR_DIG_MAX 10u + + + +#define DEF_INT_64_NBR_BITS 64u +#define DEF_INT_64_MASK 0xFFFFFFFFFFFFFFFFu + +#define DEF_INT_64U_MIN_VAL 0u +#define DEF_INT_64U_MAX_VAL 18446744073709551615u + +#define DEF_INT_64S_MIN_VAL_ONES_CPL (-9223372036854775807) +#define DEF_INT_64S_MAX_VAL_ONES_CPL 9223372036854775807 + +#define DEF_INT_64S_MIN_VAL (DEF_INT_64S_MIN_VAL_ONES_CPL - 1) +#define DEF_INT_64S_MAX_VAL DEF_INT_64S_MAX_VAL_ONES_CPL + +#define DEF_INT_64U_NBR_DIG_MIN 1u +#define DEF_INT_64U_NBR_DIG_MAX 20u + +#define DEF_INT_64S_NBR_DIG_MIN 19u +#define DEF_INT_64S_NBR_DIG_MAX 19u + + + /* --------------- CPU INTEGER DEFINES ---------------- */ +#define DEF_INT_CPU_NBR_BITS (CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS) +#define DEF_INT_CPU_NBR_BITS_MAX (CPU_CFG_DATA_SIZE_MAX * DEF_OCTET_NBR_BITS) + + + +#if (DEF_INT_CPU_NBR_BITS == DEF_INT_08_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_08_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_08U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_08U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_08S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_08S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_08S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_08S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_16_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_16_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_16U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_16U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_16S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_16S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_16S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_16S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_32_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_32_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_32U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_32U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_32S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_32S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_32S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_32S_MAX_VAL_ONES_CPL + + + +#elif (DEF_INT_CPU_NBR_BITS == DEF_INT_64_NBR_BITS) + + +#define DEF_INT_CPU_MASK DEF_INT_64_MASK + +#define DEF_INT_CPU_U_MIN_VAL DEF_INT_64U_MIN_VAL +#define DEF_INT_CPU_U_MAX_VAL DEF_INT_64U_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL DEF_INT_64S_MIN_VAL +#define DEF_INT_CPU_S_MAX_VAL DEF_INT_64S_MAX_VAL + +#define DEF_INT_CPU_S_MIN_VAL_ONES_CPL DEF_INT_64S_MIN_VAL_ONES_CPL +#define DEF_INT_CPU_S_MAX_VAL_ONES_CPL DEF_INT_64S_MAX_VAL_ONES_CPL + + + +#else + +#error "CPU_CFG_DATA_SIZE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + + /* ------------------- TIME DEFINES ------------------- */ +#define DEF_TIME_NBR_DAY_PER_WK 7u +#define DEF_TIME_NBR_DAY_PER_YR 365u +#define DEF_TIME_NBR_DAY_PER_YR_LEAP 366u + +#define DEF_TIME_NBR_HR_PER_DAY 24u +#define DEF_TIME_NBR_HR_PER_WK (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_HR_PER_YR (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_HR_PER_YR_LEAP (DEF_TIME_NBR_HR_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_MIN_PER_HR 60u +#define DEF_TIME_NBR_MIN_PER_DAY (DEF_TIME_NBR_MIN_PER_HR * DEF_TIME_NBR_HR_PER_DAY ) +#define DEF_TIME_NBR_MIN_PER_WK (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_MIN_PER_YR (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_MIN_PER_YR_LEAP (DEF_TIME_NBR_MIN_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_SEC_PER_MIN 60u +#define DEF_TIME_NBR_SEC_PER_HR (DEF_TIME_NBR_SEC_PER_MIN * DEF_TIME_NBR_MIN_PER_HR ) +#define DEF_TIME_NBR_SEC_PER_DAY (DEF_TIME_NBR_SEC_PER_HR * DEF_TIME_NBR_HR_PER_DAY ) +#define DEF_TIME_NBR_SEC_PER_WK (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_WK ) +#define DEF_TIME_NBR_SEC_PER_YR (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_YR ) +#define DEF_TIME_NBR_SEC_PER_YR_LEAP (DEF_TIME_NBR_SEC_PER_DAY * DEF_TIME_NBR_DAY_PER_YR_LEAP) + +#define DEF_TIME_NBR_mS_PER_SEC 1000u +#define DEF_TIME_NBR_uS_PER_SEC 1000000u +#define DEF_TIME_NBR_nS_PER_SEC 1000000000u + + +/* +********************************************************************************************************* +* ERROR CODES +* +* Note(s) : (1) All library error codes are #define'd in 'lib_def.h'; +********************************************************************************************************* +*/ + +typedef enum lib_err { + + LIB_ERR_NONE = 0u, + + LIB_MEM_ERR_NONE = 10000u, + LIB_MEM_ERR_NULL_PTR = 10001u, /* Ptr arg(s) passed NULL ptr(s). */ + + LIB_MEM_ERR_INVALID_MEM_SIZE = 10100u, /* Invalid mem size. */ + LIB_MEM_ERR_INVALID_MEM_ALIGN = 10101u, /* Invalid mem align. */ + LIB_MEM_ERR_INVALID_SEG_SIZE = 10110u, /* Invalid mem seg size. */ + LIB_MEM_ERR_INVALID_SEG_OVERLAP = 10111u, /* Invalid mem seg overlaps other mem seg(s). */ + LIB_MEM_ERR_INVALID_SEG_EXISTS = 10112u, /* Invalid mem seg already exists. */ + LIB_MEM_ERR_INVALID_POOL = 10120u, /* Invalid mem pool. */ + LIB_MEM_ERR_INVALID_BLK_NBR = 10130u, /* Invalid mem pool blk nbr. */ + LIB_MEM_ERR_INVALID_BLK_SIZE = 10131u, /* Invalid mem pool blk size. */ + LIB_MEM_ERR_INVALID_BLK_ALIGN = 10132u, /* Invalid mem pool blk align. */ + LIB_MEM_ERR_INVALID_BLK_IX = 10133u, /* Invalid mem pool ix. */ + LIB_MEM_ERR_INVALID_BLK_ADDR = 10135u, /* Invalid mem pool blk addr. */ + LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL = 10136u, /* Mem pool blk addr already in mem pool. */ + + LIB_MEM_ERR_SEG_EMPTY = 10200u, /* Mem seg empty; i.e. NO avail mem in seg. */ + LIB_MEM_ERR_SEG_OVF = 10201u, /* Mem seg ovf; i.e. req'd mem ovfs rem mem in seg. */ + LIB_MEM_ERR_POOL_FULL = 10205u, /* Mem pool full; i.e. all mem blks avail in mem pool. */ + LIB_MEM_ERR_POOL_EMPTY = 10206u, /* Mem pool empty; i.e. NO mem blks avail in mem pool. */ + LIB_MEM_ERR_POOL_UNLIMITED = 10207u, /* Mem pool is unlimited. */ + + LIB_MEM_ERR_HEAP_EMPTY = 10210u, /* Heap seg empty; i.e. NO avail mem in heap. */ + LIB_MEM_ERR_HEAP_OVF = 10211u, /* Heap seg ovf; i.e. req'd mem ovfs rem mem in heap. */ + LIB_MEM_ERR_HEAP_NOT_FOUND = 10215u /* Heap seg NOT found. */ + +} LIB_ERR; + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* TRACING +********************************************************************************************************* +*/ + + /* Trace level, default to TRACE_LEVEL_OFF. */ +#ifndef TRACE_LEVEL_OFF +#define TRACE_LEVEL_OFF 0u +#endif + +#ifndef TRACE_LEVEL_INFO +#define TRACE_LEVEL_INFO 1u +#endif + +#ifndef TRACE_LEVEL_DBG +#define TRACE_LEVEL_DBG 2u +#endif + +#ifndef TRACE_LEVEL_LOG +#define TRACE_LEVEL_LOG 3u +#endif + + +/* +********************************************************************************************************* +* BIT MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_BIT() +* +* Description : Create bit mask with single, specified bit set. +* +* Argument(s) : bit Bit number of bit to set. +* +* Return(s) : Bit mask with single, specified bit set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit' SHOULD be a non-negative integer. +* +* (2) (a) 'bit' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT(bit) (1uL << (bit)) + + +/* +********************************************************************************************************* +* DEF_BITxx() +* +* Description : Create bit mask of specified bit size with single, specified bit set. +* +* Argument(s) : bit Bit number of bit to set. +* +* Return(s) : Bit mask with single, specified bit set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit' SHOULD be a non-negative integer. +* +* (2) (a) 'bit' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is cast to specified integer data type size. +* +* (3) Ideally, DEF_BITxx() macro's should be named DEF_BIT_xx(); however, these names already +* previously-released for bit constant #define's (see 'STANDARD DEFINES BIT DEFINES'). +********************************************************************************************************* +*/ + +#define DEF_BIT08(bit) ((CPU_INT08U)((CPU_INT08U)1u << (bit))) + +#define DEF_BIT16(bit) ((CPU_INT16U)((CPU_INT16U)1u << (bit))) + +#define DEF_BIT32(bit) ((CPU_INT32U)((CPU_INT32U)1u << (bit))) + +#define DEF_BIT64(bit) ((CPU_INT64U)((CPU_INT64U)1u << (bit))) + + +/* +********************************************************************************************************* +* DEF_BIT_MASK() +* +* Description : Shift a bit mask. +* +* Argument(s) : bit_mask Bit mask to shift. +* +* bit_shift Number of bit positions to left-shift bit mask. +* +* Return(s) : Shifted bit mask. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) 'bit_mask' SHOULD be an unsigned integer. +* +* (b) 'bit_shift' SHOULD be a non-negative integer. +* +* (2) 'bit_shift' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT_MASK(bit_mask, bit_shift) ((bit_mask) << (bit_shift)) + + +/* +********************************************************************************************************* +* DEF_BIT_MASK_xx() +* +* Description : Shift a bit mask of specified bit size. +* +* Argument(s) : bit_mask Bit mask to shift. +* +* bit_shift Number of bit positions to left-shift bit mask. +* +* Return(s) : Shifted bit mask. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) 'bit_mask' SHOULD be an unsigned integer. +* +* (b) 'bit_shift' SHOULD be a non-negative integer. +* +* (2) 'bit_shift' values that overflow the target CPU &/or compiler environment (e.g. negative +* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors. +********************************************************************************************************* +*/ + +#define DEF_BIT_MASK_08(bit_mask, bit_shift) ((CPU_INT08U)((CPU_INT08U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_16(bit_mask, bit_shift) ((CPU_INT16U)((CPU_INT16U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_32(bit_mask, bit_shift) ((CPU_INT32U)((CPU_INT32U)(bit_mask) << (bit_shift))) + +#define DEF_BIT_MASK_64(bit_mask, bit_shift) ((CPU_INT64U)((CPU_INT64U)(bit_mask) << (bit_shift))) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD() +* +* Description : Create & shift a contiguous bit field. +* +* Argument(s) : bit_field Number of contiguous bits to set in the bit field. +* +* bit_shift Number of bit positions to left-shift bit field. +* +* Return(s) : Shifted bit field. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit_field' & 'bit_shift' SHOULD be non-negative integers. +* +* (2) (a) 'bit_field'/'bit_shift' values that overflow the target CPU &/or compiler +* environment (e.g. negative or greater-than-CPU-data-size values) MAY generate +* compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is suffixed with 'L'ong integer modifier. +* +* This may still be insufficient for CPUs &/or compilers that support 'long long' +* integer data types, in which case 'LL' integer modifier should be suffixed. +* However, since almost all 16- & 32-bit CPUs & compilers support 'long' integer +* data types but many may NOT support 'long long' integer data types, only 'long' +* integer data types & modifiers are supported. +* +* See also 'DEF_BIT_FIELD_xx() Note #1b'. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD(bit_field, bit_shift) ((((bit_field) >= DEF_INT_CPU_NBR_BITS) ? (DEF_INT_CPU_U_MAX_VAL) \ + : (DEF_BIT(bit_field) - 1uL)) \ + << (bit_shift)) + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_xx() +* +* Description : Create & shift a contiguous bit field of specified bit size. +* +* Argument(s) : bit_field Number of contiguous bits to set in the bit field. +* +* bit_shift Number of bit positions to left-shift bit field. +* +* Return(s) : Shifted bit field. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'bit_field' & 'bit_shift' SHOULD be non-negative integers. +* +* (2) (a) 'bit_field'/'bit_shift' values that overflow the target CPU &/or compiler +* environment (e.g. negative or greater-than-CPU-data-size values) MAY generate +* compiler warnings &/or errors. +* +* (b) To avoid overflowing any target CPU &/or compiler's integer data type, unsigned +* bit constant '1' is cast to specified integer data type size. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_08(bit_field, bit_shift) ((CPU_INT08U)((((CPU_INT08U)(bit_field) >= (CPU_INT08U)DEF_INT_08_NBR_BITS) ? (CPU_INT08U)(DEF_INT_08U_MAX_VAL) \ + : (CPU_INT08U)(DEF_BIT08(bit_field) - (CPU_INT08U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_16(bit_field, bit_shift) ((CPU_INT16U)((((CPU_INT16U)(bit_field) >= (CPU_INT16U)DEF_INT_16_NBR_BITS) ? (CPU_INT16U)(DEF_INT_16U_MAX_VAL) \ + : (CPU_INT16U)(DEF_BIT16(bit_field) - (CPU_INT16U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_32(bit_field, bit_shift) ((CPU_INT32U)((((CPU_INT32U)(bit_field) >= (CPU_INT32U)DEF_INT_32_NBR_BITS) ? (CPU_INT32U)(DEF_INT_32U_MAX_VAL) \ + : (CPU_INT32U)(DEF_BIT32(bit_field) - (CPU_INT32U)1u)) \ + << (bit_shift))) + +#define DEF_BIT_FIELD_64(bit_field, bit_shift) ((CPU_INT64U)((((CPU_INT64U)(bit_field) >= (CPU_INT64U)DEF_INT_64_NBR_BITS) ? (CPU_INT64U)(DEF_INT_64U_MAX_VAL) \ + : (CPU_INT64U)(DEF_BIT64(bit_field) - (CPU_INT64U)1u)) \ + << (bit_shift))) + + +/* +********************************************************************************************************* +* DEF_BIT_SET() +* +* Description : Set specified bit(s) in a value. +* +* Argument(s) : val Value to modify by setting specified bit(s). +* +* mask Mask of bits to set. +* +* Return(s) : Modified value with specified bit(s) set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_SET(val, mask) ((val) = ((val) | (mask))) + + +/* +********************************************************************************************************* +* DEF_BIT_SET_xx() +* +* Description : Set specified bit(s) in a value of specified bit size. +* +* Argument(s) : val Value to modify by setting specified bit(s). +* +* mask Mask of bits to set. +* +* Return(s) : Modified value with specified bit(s) set. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) These macros are deprecated and should be replaced by the DEF_BIT_SET macro. +********************************************************************************************************* +*/ + +#define DEF_BIT_SET_08(val, mask) (CPU_INT08U)DEF_BIT_SET((val), (CPU_INT08U)(mask)) + +#define DEF_BIT_SET_16(val, mask) (CPU_INT16U)DEF_BIT_SET((val), (CPU_INT16U)(mask)) + +#define DEF_BIT_SET_32(val, mask) (CPU_INT32U)DEF_BIT_SET((val), (CPU_INT32U)(mask)) + +#define DEF_BIT_SET_64(val, mask) (CPU_INT64U)DEF_BIT_SET((val), (CPU_INT64U)(mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_CLR_xx() +* +* Description : Clear specified bit(s) in a value of specified bit size. +* +* Argument(s) : val Value to modify by clearing specified bit(s). +* +* mask Mask of bits to clear. +* +* Return(s) : Modified value with specified bit(s) clear. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_CLR_08(val, mask) ((val) = (CPU_INT08U)(((CPU_INT08U)(val)) & (CPU_INT08U)(~((CPU_INT08U)(mask))))) + +#define DEF_BIT_CLR_16(val, mask) ((val) = (CPU_INT16U)(((CPU_INT16U)(val)) & (CPU_INT16U)(~((CPU_INT16U)(mask))))) + +#define DEF_BIT_CLR_32(val, mask) ((val) = (CPU_INT32U)(((CPU_INT32U)(val)) & (CPU_INT32U)(~((CPU_INT32U)(mask))))) + +#define DEF_BIT_CLR_64(val, mask) ((val) = (CPU_INT64U)(((CPU_INT64U)(val)) & (CPU_INT64U)(~((CPU_INT64U)(mask))))) + + +/* +********************************************************************************************************* +* DEF_BIT_CLR() +* +* Description : Clear specified bit(s) in a value. +* +* Argument(s) : val Value to modify by clearing specified bit(s). +* +* mask Mask of bits to clear. +* +* Return(s) : Modified value with specified bit(s) clear. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_08) + +#define DEF_BIT_CLR(val, mask) ((sizeof((val)) == CPU_WORD_SIZE_08) ? DEF_BIT_CLR_08((val), (mask)) : 0) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_16) + +#define DEF_BIT_CLR(val, mask) ((sizeof((val)) == CPU_WORD_SIZE_08) ? DEF_BIT_CLR_08((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_16) ? DEF_BIT_CLR_16((val), (mask)) : 0)) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_32) + +#define DEF_BIT_CLR(val, mask) ((sizeof((val)) == CPU_WORD_SIZE_08) ? DEF_BIT_CLR_08((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_16) ? DEF_BIT_CLR_16((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_32) ? DEF_BIT_CLR_32((val), (mask)) : 0))) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_64) + +#define DEF_BIT_CLR(val, mask) ((sizeof((val)) == CPU_WORD_SIZE_08) ? DEF_BIT_CLR_08((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_16) ? DEF_BIT_CLR_16((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_32) ? DEF_BIT_CLR_32((val), (mask)) : \ + ((sizeof((val)) == CPU_WORD_SIZE_64) ? DEF_BIT_CLR_64((val), (mask)) : 0)))) + +#else + +#error "CPU_CFG_DATA_SIZE_MAX illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* DEF_BIT_TOGGLE() +* +* Description : Toggles specified bit(s) in a value. +* +* Argument(s) : val Value to modify by toggling specified bit(s). +* +* mask Mask of bits to toggle. +* +* Return(s) : Modified value with specified bit(s) toggled. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_TOGGLE(val, mask) ((val) ^= (mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_RD() +* +* Description : Reads a 'val' field, masked and shifted, given by mask 'field_mask'. +* +* Argument(s) : val Value to read from. +* +* field_mask Mask of field to read. See note #1, #2 and #3. +* +* Return(s) : Field value, masked and right-shifted to bit position 0. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must NOT be 0. +* +* (2) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (3) 'val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_RD(val, field_mask) (((val) & (field_mask)) / ((field_mask) & ((~(field_mask)) + 1u))) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_ENC() +* +* Description : Encodes given 'field_val' at position given by mask 'field_mask'. +* +* Argument(s) : field_val Value to encode. +* +* field_mask Mask of field to read. See note #1 and #2. +* +* Return(s) : Field value, masked and left-shifted to field position. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (2) 'field_val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_ENC(field_val, field_mask) (((field_val) * ((field_mask) & ((~(field_mask)) + 1u))) & (field_mask)) + + +/* +********************************************************************************************************* +* DEF_BIT_FIELD_WR() +* +* Description : Writes 'field_val' field at position given by mask 'field_mask' in variable 'var'. +* +* Argument(s) : var Variable to write field to. See note #2. +* +* field_val Desired value for field. See note #2. +* +* field_mask Mask of field to write to. See note #1 and #2. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'field_mask' argument must contain a mask with contiguous set bits. +* +* (2) 'var', 'field_val' & 'field_mask' SHOULD be unsigned integers. +********************************************************************************************************* +*/ + +#define DEF_BIT_FIELD_WR(var, field_val, field_mask) (var) = (((var) & ~(field_mask)) | DEF_BIT_FIELD_ENC((field_val), (field_mask))) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_SET() +* +* Description : Determine if specified bit(s) in a value are set. +* +* Argument(s) : val Value to check for specified bit(s) set. +* +* mask Mask of bits to check if set (see Note #2). +* +* Return(s) : DEF_YES, if ALL specified bit(s) are set in value. +* +* DEF_NO, if ALL specified bit(s) are NOT set in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_SET(val, mask) (((((val) & (mask)) == (mask)) && \ + ((mask) != 0u)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_CLR() +* +* Description : Determine if specified bit(s) in a value are clear. +* +* Argument(s) : val Value to check for specified bit(s) clear. +* +* mask Mask of bits to check if clear (see Note #2). +* +* Return(s) : DEF_YES, if ALL specified bit(s) are clear in value. +* +* DEF_NO, if ALL specified bit(s) are NOT clear in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_CLR(val, mask) (((((val) & (mask)) == 0u) && \ + ((mask) != 0u)) ? (DEF_YES) : (DEF_NO)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_SET_ANY() +* +* Description : Determine if any specified bit(s) in a value are set. +* +* Argument(s) : val Value to check for specified bit(s) set. +* +* mask Mask of bits to check if set (see Note #2). +* +* Return(s) : DEF_YES, if ANY specified bit(s) are set in value. +* +* DEF_NO, if ALL specified bit(s) are NOT set in value. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_SET_ANY(val, mask) ((((val) & (mask)) == 0u) ? (DEF_NO ) : (DEF_YES)) + + +/* +********************************************************************************************************* +* DEF_BIT_IS_CLR_ANY() +* +* Description : Determine if any specified bit(s) in a value are clear. +* +* Argument(s) : val Value to check for specified bit(s) clear. +* +* mask Mask of bits to check if clear (see Note #2). +* +* Return(s) : DEF_YES, if ANY specified bit(s) are clear in value. +* +* DEF_NO, if ALL specified bit(s) are NOT clear in value. +* +* Note(s) : (1) 'val' & 'mask' SHOULD be unsigned integers. +* +* (2) NULL 'mask' allowed; returns 'DEF_NO' since NO mask bits specified. +********************************************************************************************************* +*/ + +#define DEF_BIT_IS_CLR_ANY(val, mask) ((((val) & (mask)) == (mask)) ? (DEF_NO ) : (DEF_YES)) + + +/* +********************************************************************************************************* +* VALUE MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_CHK_VAL_MIN() +* +* Description : Validate a value as greater than or equal to a specified minimum value. +* +* Argument(s) : val Value to validate. +* +* val_min Minimum value to test. +* +* Return(s) : DEF_OK, Value is greater than or equal to minimum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL_MIN() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) 'val' and 'val_min' are compared to 1 instead of 0 to avoid warning generated for +* unsigned numbers. +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL_MIN(val, val_min) (((!(((val) >= 1) && ((val_min) < 1))) && \ + ((((val_min) >= 1) && ((val) < 1)) || \ + ((val) < (val_min)))) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_CHK_VAL_MAX() +* +* Description : Validate a value as less than or equal to a specified maximum value. +* +* Argument(s) : val Value to validate. +* +* val_max Maximum value to test. +* +* Return(s) : DEF_OK, Value is less than or equal to maximum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL_MAX() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) 'val' and 'val_max' are compared to 1 instead of 0 to avoid warning generated for +* unsigned numbers. +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL_MAX(val, val_max) (((!(((val_max) >= 1) && ((val) < 1))) && \ + ((((val) >= 1) && ((val_max) < 1)) || \ + ((val) > (val_max)))) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_CHK_VAL() +* +* Description : Validate a value as greater than or equal to a specified minimum value & less than or +* equal to a specified maximum value. +* +* Argument(s) : val Value to validate. +* +* val_min Minimum value to test. +* +* val_max Maximum value to test. +* +* Return(s) : DEF_OK, Value is greater than or equal to minimum value AND +* less than or equal to maximum value. +* +* DEF_FAIL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) DEF_CHK_VAL() avoids directly comparing any two values if only one of the values +* is negative since the negative value might be incorrectly promoted to an arbitrary +* unsigned value if the other value to compare is unsigned. +* +* (2) Validation of values is limited to the range supported by the compiler &/or target +* environment. All other values that underflow/overflow the supported range will +* modulo/wrap into the supported range as arbitrary signed or unsigned values. +* +* Therefore, any values that underflow the most negative signed value or overflow +* the most positive unsigned value supported by the compiler &/or target environment +* cannot be validated : +* +* ( N-1 N ] +* ( -(2 ) , 2 - 1 ] +* ( ] +* +* where +* N Number of data word bits supported by the compiler +* &/or target environment +* +* (a) Note that the most negative value, -2^(N-1), is NOT included in the supported +* range since many compilers do NOT always correctly handle this value. +* +* (3) DEF_CHK_VAL() does NOT validate that the maximum value ('val_max') is greater than +* or equal to the minimum value ('val_min'). +********************************************************************************************************* +*/ + +#define DEF_CHK_VAL(val, val_min, val_max) (((DEF_CHK_VAL_MIN((val), (val_min)) == DEF_FAIL) || \ + (DEF_CHK_VAL_MAX((val), (val_max)) == DEF_FAIL)) ? DEF_FAIL : DEF_OK) + + +/* +********************************************************************************************************* +* DEF_GET_U_MAX_VAL() +* +* Description : Get the maximum unsigned value that can be represented in an unsigned integer variable +* of the same data type size as an object. +* +* Argument(s) : obj Object or data type to return maximum unsigned value (see Note #1). +* +* Return(s) : Maximum unsigned integer value that can be represented by the object, if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'obj' SHOULD be an integer object or data type but COULD also be a character or +* pointer object or data type. +********************************************************************************************************* +*/ + +#if (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_08) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : 0) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_16) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : 0)) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_32) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_32) ? DEF_INT_32U_MAX_VAL : 0))) + + +#elif (CPU_CFG_DATA_SIZE_MAX == CPU_WORD_SIZE_64) + +#define DEF_GET_U_MAX_VAL(obj) ((sizeof(obj) == CPU_WORD_SIZE_08) ? DEF_INT_08U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_16) ? DEF_INT_16U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_32) ? DEF_INT_32U_MAX_VAL : \ + ((sizeof(obj) == CPU_WORD_SIZE_64) ? DEF_INT_64U_MAX_VAL : 0)))) + +#else + +#error "CPU_CFG_DATA_SIZE_MAX illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MATH MACRO'S +* +* Note(s) : (1) Ideally, ALL mathematical macro's & functions SHOULD be defined in the custom mathematics +* library ('lib_math.*'). #### However, to maintain backwards compatibility with previously- +* released modules, mathematical macro & function definitions should only be moved to the +* custom mathematics library once all previously-released modules are updated to include the +* custom mathematics library. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEF_MIN() +* +* Description : Determine the minimum of two values. +* +* Argument(s) : a First value. +* +* b Second value. +* +* Return(s) : Minimum of the two values. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +/* +********************************************************************************************************* +* DEF_MAX() +* +* Description : Determine the maximum of two values. +* +* Argument(s) : a First value. +* +* b Second value. +* +* Return(s) : Maximum of the two values. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_MAX(a, b) (((a) > (b)) ? (a) : (b)) + + +/* +********************************************************************************************************* +* DEF_ABS() +* +* Description : Determine the absolute value of a value. +* +* Argument(s) : a Value to calculate absolute value. +* +* Return(s) : Absolute value of the value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define DEF_ABS(a) (((a) < 0) ? (-(a)) : (a)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'lib_def.h Note #1a'. */ +#if (CPU_CORE_VERSION < 12900u) +#error "CPU_CORE_VERSION [SHOULD be >= V1.29.00]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_def.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib def module include. */ + diff --git a/rtos/uC-LIB/lib_math.c b/rtos/uC-LIB/lib_math.c new file mode 100644 index 00000000..0a2ab5ad --- /dev/null +++ b/rtos/uC-LIB/lib_math.c @@ -0,0 +1,270 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* MATHEMATIC OPERATIONS +* +* Filename : lib_math.c +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_MATH_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + +RAND_NBR Math_RandSeedCur; /* Cur rand nbr seed. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* Math_Init() +* +* Description : (1) Initialize Mathematic Module : +* +* (a) Initialize random number seed value +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (2) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "if rand() +* is called before any calls to srand() are made, the same sequence shall be generated +* as when srand() is first called with a seed value of 1". +********************************************************************************************************* +*/ + +void Math_Init (void) +{ + Math_RandSetSeed((RAND_NBR)RAND_SEED_INIT_VAL); /* See Note #2. */ +} + + +/* +********************************************************************************************************* +* Math_RandSetSeed() +* +* Description : Set the current pseudo-random number generator seed. +* +* Argument(s) : seed Initial (or current) value to set for the pseudo-random number sequence. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "srand() +* ... uses the argument as a seed for a new sequence of pseudo-random numbers to be +* returned by subsequent calls to rand()". +* +* (2) 'Math_RandSeedCur' MUST always be accessed exclusively in critical sections. +* +* See also 'Math_Rand() Note #1b'. +********************************************************************************************************* +*/ + +void Math_RandSetSeed (RAND_NBR seed) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + Math_RandSeedCur = seed; + CPU_CRITICAL_EXIT(); +} + + +/* +********************************************************************************************************* +* Math_Rand() +* +* Description : Calculate the next pseudo-random number. +* +* Argument(s) : none. +* +* Return(s) : Next pseudo-random number in the sequence after 'Math_RandSeedCur'. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) The pseudo-random number generator is implemented as a Linear Congruential +* Generator (LCG). +* +* (b) The pseudo-random number generated is in the range [0, RAND_LCG_PARAM_M]. +* +* See also 'Math_RandSeed() Note #1'. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "rand() +* ... need not be reentrant ... [and] is not required to be thread-safe". +* +* (b) However, in order to implement Math_Rand() as re-entrant; 'Math_RandSeedCur' MUST +* always be accessed & updated exclusively in critical sections. +* +* See also 'Math_RandSeed() Note #2'. +********************************************************************************************************* +*/ + +RAND_NBR Math_Rand (void) +{ + RAND_NBR seed; + RAND_NBR rand_nbr; + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + seed = Math_RandSeedCur; + rand_nbr = Math_RandSeed(seed); + Math_RandSeedCur = rand_nbr; + CPU_CRITICAL_EXIT(); + + return (rand_nbr); +} + + +/* +********************************************************************************************************* +* Math_RandSeed() +* +* Description : Calculate the next pseudo-random number. +* +* Argument(s) : seed Initial (or current) value for the pseudo-random number sequence. +* +* Return(s) : Next pseudo-random number in the sequence after 'seed'. +* +* Caller(s) : Math_Rand(), +* Application. +* +* Note(s) : (1) (a) BSD/ANSI-C implements rand() as a Linear Congruential Generator (LCG) : +* +* (A) random_number = [(a * random_number ) + b] modulo m +* n + 1 n +* +* where +* (1) (a) random_number Next random number to generate +* n+1 +* (b) random_number Previous random number generated +* n +* +* (2) a = RAND_LCG_PARAM_A LCG multiplier +* (3) b = RAND_LCG_PARAM_B LCG incrementor +* (4) m = RAND_LCG_PARAM_M + 1 LCG modulus +* +* (b) The pseudo-random number generated is in the range [0, RAND_LCG_PARAM_M]. +* + See also 'lib_math.h RANDOM NUMBER DEFINES Note #1b'. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "rand() +* ... need not be reentrant ... [and] is not required to be thread-safe". +* +* (b) However, Math_RandSeed() is re-entrant since it calculates the next random number +* using ONLY local variables. +********************************************************************************************************* +*/ + +RAND_NBR Math_RandSeed (RAND_NBR seed) +{ + RAND_NBR rand_nbr; + + + rand_nbr = (((RAND_NBR)RAND_LCG_PARAM_A * seed) + (RAND_NBR)RAND_LCG_PARAM_B) % ((RAND_NBR)RAND_LCG_PARAM_M + 1u); + + return (rand_nbr); +} + diff --git a/rtos/uC-LIB/lib_math.h b/rtos/uC-LIB/lib_math.h new file mode 100644 index 00000000..7f5e6f4b --- /dev/null +++ b/rtos/uC-LIB/lib_math.h @@ -0,0 +1,287 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* MATHEMATIC OPERATIONS +* +* Filename : lib_math.h +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This mathematics library header file is protected from multiple pre-processor inclusion +* through use of the mathematics library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_MATH_MODULE_PRESENT /* See Note #1. */ +#define LIB_MATH_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_*.* +* +* where +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_MATH_MODULE +#define LIB_MATH_EXT +#else +#define LIB_MATH_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* RANDOM NUMBER DEFINES +* +* Note(s) : (1) (a) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that "if rand() +* is called before any calls to srand() are made, the same sequence shall be generated +* as when srand() is first called with a seed value of 1". +* +* (b) (1) BSD/ANSI-C implements rand() as a Linear Congruential Generator (LCG) : +* +* (A) random_number = [(a * random_number ) + b] modulo m +* n + 1 n +* +* where +* (1) (a) random_number Next random number to generate +* n+1 +* (b) random_number Previous random number generated +* n +* (c) random_number Initial random number seed +* 0 See also Note #1a +* +* (2) a = 1103515245 LCG multiplier +* (3) b = 12345 LCG incrementor +* (4) m = RAND_MAX + 1 LCG modulus See also Note #1b2 +* +* (2) (A) IEEE Std 1003.1, 2004 Edition, Section 'rand() : DESCRIPTION' states that +* "rand() ... shall compute a sequence of pseudo-random integers in the range +* [0, {RAND_MAX}] with a period of at least 2^32". +* +* (B) However, BSD/ANSI-C 'stdlib.h' defines "RAND_MAX" as "0x7fffffff", or 2^31; +* which therefore limits the range AND period to no more than 2^31. +********************************************************************************************************* +*/ + +#define RAND_SEED_INIT_VAL 1u /* See Note #1a. */ + +#define RAND_LCG_PARAM_M 0x7FFFFFFFu /* See Note #1b2B. */ +#define RAND_LCG_PARAM_A 1103515245u /* See Note #1b1A2. */ +#define RAND_LCG_PARAM_B 12345u /* See Note #1b1A3. */ + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* RANDOM NUMBER DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_INT32U RAND_NBR; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACROS +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MATH_IS_PWR2() +* +* Description : Determine if a value is a power of 2. +* +* Argument(s) : nbr Value. +* +* Return(s) : DEF_YES, 'nbr' is a power of 2. +* +* DEF_NO, 'nbr' is not a power of 2. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_IS_PWR2(nbr) ((((nbr) != 0u) && (((nbr) & ((nbr) - 1u)) == 0u)) ? DEF_YES : DEF_NO) + + +/* +********************************************************************************************************* +* MATH_ROUND_INC_UP_PWR2() +* +* Description : Round value up to the next (power of 2) increment. +* +* Argument(s) : nbr Value to round. +* +* inc Increment to use. MUST be a power of 2. +* +* Return(s) : Rounded up value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_ROUND_INC_UP_PWR2(nbr, inc) (((nbr) & ~((inc) - 1)) + (((nbr) & ((inc) - 1)) == 0 ? 0 : (inc))) + + +/* +********************************************************************************************************* +* MATH_ROUND_INC_UP() +* +* Description : Round value up to the next increment. +* +* Argument(s) : nbr Value to round. +* +* inc Increment to use. +* +* Return(s) : Rounded up value. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#define MATH_ROUND_INC_UP(nbr, inc) (((nbr) + ((inc) - 1)) / (inc) * (inc)) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void Math_Init (void); + + /* ------------------ RAND NBR FNCTS ------------------ */ +void Math_RandSetSeed(RAND_NBR seed); + +RAND_NBR Math_Rand (void); + +RAND_NBR Math_RandSeed (RAND_NBR seed); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_math.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib math module include. */ + diff --git a/rtos/uC-LIB/lib_mem.c b/rtos/uC-LIB/lib_mem.c new file mode 100644 index 00000000..91524a82 --- /dev/null +++ b/rtos/uC-LIB/lib_mem.c @@ -0,0 +1,2844 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* STANDARD MEMORY OPERATIONS +* +* Filename : lib_mem.c +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_MEM_MODULE +#include "lib_mem.h" +#include "lib_math.h" +#include "lib_str.h" + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +#ifndef LIB_MEM_CFG_HEAP_BASE_ADDR +CPU_INT08U Mem_Heap[LIB_MEM_CFG_HEAP_SIZE]; /* Mem heap. */ +#endif + +MEM_SEG Mem_SegHeap; /* Heap mem seg. */ +#endif + +MEM_SEG *Mem_SegHeadPtr; /* Ptr to head of seg list. */ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static void Mem_SegCreateCritical (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T padding_align, + CPU_SIZE_T size); + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +static MEM_SEG *Mem_SegOverlapChkCritical( CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + LIB_ERR *p_err); +#endif + +static void *Mem_SegAllocInternal (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +static void *Mem_SegAllocExtCritical ( MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +static void Mem_DynPoolCreateInternal(const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_padding_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +static void Mem_SegAllocTrackCritical(const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err); +#endif + +#if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \ + (LIB_MEM_CFG_HEAP_SIZE > 0u)) +static CPU_BOOLEAN Mem_PoolBlkIsValidAddr ( MEM_POOL *p_pool, + void *p_mem); +#endif + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +********************************************************************************************************* +* GLOBAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Mem_Init() +* +* Description : (1) Initializes Memory Management Module : +* +* (a) Initialize heap memory pool +* (b) Initialize memory pool table +* +* +* Argument(s) : none. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (2) Mem_Init() MUST be called ... : +* +* (a) ONLY ONCE from a product's application; ... +* (b) BEFORE product's application calls any memory library module function(s) +********************************************************************************************************* +*/ + +void Mem_Init (void) +{ + + /* ------------------ INIT SEG LIST ------------------- */ + Mem_SegHeadPtr = DEF_NULL; + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + { + LIB_ERR err; + CPU_ADDR heap_base_addr; + + + /* ------------------ INIT HEAP SEG ------------------- */ +#ifdef LIB_MEM_CFG_HEAP_BASE_ADDR + heap_base_addr = LIB_MEM_CFG_HEAP_BASE_ADDR; +#else + heap_base_addr = (CPU_ADDR)&Mem_Heap[0u]; +#endif + + Mem_SegCreate("Heap", + &Mem_SegHeap, /* Create heap seg. */ + heap_base_addr, + LIB_MEM_CFG_HEAP_SIZE, + LIB_MEM_PADDING_ALIGN_NONE, + &err); + if (err != LIB_MEM_ERR_NONE) { + CPU_SW_EXCEPTION(;); + } + } +#endif +} + + +/* +********************************************************************************************************* +* Mem_Clr() +* +* Description : Clears data buffer (see Note #2). +* +* Argument(s) : pmem Pointer to memory buffer to clear. +* +* size Number of data buffer octets to clear (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null clears allowed (i.e. zero-length clears). +* +* See also 'Mem_Set() Note #1'. +* +* (2) Clear data by setting each data octet to 0. +********************************************************************************************************* +*/ + +void Mem_Clr (void *pmem, + CPU_SIZE_T size) +{ + Mem_Set(pmem, + 0u, /* See Note #2. */ + size); +} + + +/* +********************************************************************************************************* +* Mem_Set() +* +* Description : Fills data buffer with specified data octet. +* +* Argument(s) : pmem Pointer to memory buffer to fill with specified data octet. +* +* data_val Data fill octet value. +* +* size Number of data buffer octets to fill (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null sets allowed (i.e. zero-length sets). +* +* (2) For best CPU performance, optimized to fill data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +void Mem_Set (void *pmem, + CPU_INT08U data_val, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_ALIGN data_align; + CPU_ALIGN *pmem_align; + CPU_INT08U *pmem_08; + CPU_DATA mem_align_mod; + CPU_DATA i; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { /* See Note #1. */ + return; + } + if (pmem == (void *)0) { + return; + } +#endif + + + data_align = 0u; + for (i = 0u; i < sizeof(CPU_ALIGN); i++) { /* Fill each data_align octet with data val. */ + data_align <<= DEF_OCTET_NBR_BITS; + data_align |= (CPU_ALIGN)data_val; + } + + size_rem = size; + mem_align_mod = (CPU_INT08U)((CPU_ADDR)pmem % sizeof(CPU_ALIGN)); /* See Note #3. */ + + pmem_08 = (CPU_INT08U *)pmem; + if (mem_align_mod != 0u) { /* If leading octets avail, ... */ + i = mem_align_mod; + while ((size_rem > 0) && /* ... start mem buf fill with leading octets ... */ + (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08++ = data_val; + size_rem -= sizeof(CPU_INT08U); + i++; + } + } + + pmem_align = (CPU_ALIGN *)pmem_08; /* See Note #2. */ + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem buf aligned on CPU_ALIGN word boundaries, */ + *pmem_align++ = data_align; /* ... fill mem buf with CPU_ALIGN-sized data. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08 = (CPU_INT08U *)pmem_align; + while (size_rem > 0) { /* Finish mem buf fill with trailing octets. */ + *pmem_08++ = data_val; + size_rem -= sizeof(CPU_INT08U); + } +} + + +/* +********************************************************************************************************* +* Mem_Copy() +* +* Description : Copies data octets from one memory buffer to another memory buffer. +* +* Argument(s) : pdest Pointer to destination memory buffer. +* +* psrc Pointer to source memory buffer. +* +* size Number of octets to copy (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null copies allowed (i.e. zero-length copies). +* +* (2) Memory buffers NOT checked for overlapping. +* +* (a) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (b) However, data octets from a source memory buffer at a higher address value SHOULD +* successfully copy to a destination memory buffer at a lower address value even +* if any octets of the memory buffers overlap as long as no individual, atomic CPU +* word copy overlaps. +* +* Since Mem_Copy() performs the data octet copy via 'CPU_ALIGN'-sized words &/or +* octets; & since 'CPU_ALIGN'-sized words MUST be accessed on word-aligned addresses +* (see Note #3b), neither 'CPU_ALIGN'-sized words nor octets at unique addresses can +* ever overlap. +* +* Therefore, Mem_Copy() SHOULD be able to successfully copy overlapping memory +* buffers as long as the source memory buffer is at a higher address value than the +* destination memory buffer. +* +* (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_ENABLED) +void Mem_Copy ( void *pdest, + const void *psrc, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_SIZE_T mem_gap_octets; + CPU_ALIGN *pmem_align_dest; + const CPU_ALIGN *pmem_align_src; + CPU_INT08U *pmem_08_dest; + const CPU_INT08U *pmem_08_src; + CPU_DATA i; + CPU_DATA mem_align_mod_dest; + CPU_DATA mem_align_mod_src; + CPU_BOOLEAN mem_aligned; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { /* See Note #1. */ + return; + } + if (pdest == (void *)0) { + return; + } + if (psrc == (void *)0) { + return; + } +#endif + + + size_rem = size; + + pmem_08_dest = ( CPU_INT08U *)pdest; + pmem_08_src = (const CPU_INT08U *)psrc; + + mem_gap_octets = (CPU_SIZE_T)(pmem_08_src - pmem_08_dest); + + + if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */ + /* See Note #4. */ + mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN)); + mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize copy for mem buf alignment. */ + if (mem_align_mod_dest != 0u) { /* If leading octets avail, ... */ + i = mem_align_mod_dest; + while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */ + (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08_dest++ = *pmem_08_src++; + size_rem -= sizeof(CPU_INT08U); + i++; + } + } + + pmem_align_dest = ( CPU_ALIGN *)pmem_08_dest; /* See Note #3. */ + pmem_align_src = (const CPU_ALIGN *)pmem_08_src; + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */ + *pmem_align_dest++ = *pmem_align_src++; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08_dest = ( CPU_INT08U *)pmem_align_dest; + pmem_08_src = (const CPU_INT08U *)pmem_align_src; + } + } + + while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */ + *pmem_08_dest++ = *pmem_08_src++; /* ... copy psrc to pdest by octets. */ + size_rem -= sizeof(CPU_INT08U); + } +} +#endif + + +/* +********************************************************************************************************* +* Mem_Move() +* +* Description : Moves data octets from one memory buffer to another memory buffer, or within the same +* memory buffer. Overlapping is correctly handled for all move operations. +* +* Argument(s) : pdest Pointer to destination memory buffer. +* +* psrc Pointer to source memory buffer. +* +* size Number of octets to move (see Note #1). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null move operations allowed (i.e. zero-length). +* +* (2) Memory buffers checked for overlapping. +* +* (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data +* words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +void Mem_Move ( void *pdest, + const void *psrc, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_SIZE_T mem_gap_octets; + CPU_ALIGN *pmem_align_dest; + const CPU_ALIGN *pmem_align_src; + CPU_INT08U *pmem_08_dest; + const CPU_INT08U *pmem_08_src; + CPU_INT08S i; + CPU_DATA mem_align_mod_dest; + CPU_DATA mem_align_mod_src; + CPU_BOOLEAN mem_aligned; + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (size < 1) { + return; + } + if (pdest == (void *)0) { + return; + } + if (psrc == (void *)0) { + return; + } +#endif + + pmem_08_src = (const CPU_INT08U *)psrc; + pmem_08_dest = ( CPU_INT08U *)pdest; + if (pmem_08_src > pmem_08_dest) { + Mem_Copy(pdest, psrc, size); + return; + } + + size_rem = size; + + pmem_08_dest = ( CPU_INT08U *)pdest + size - 1; + pmem_08_src = (const CPU_INT08U *)psrc + size - 1; + + mem_gap_octets = (CPU_SIZE_T)(pmem_08_dest - pmem_08_src); + + + if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */ + + /* See Note #4. */ + mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN)); + mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize copy for mem buf alignment. */ + if (mem_align_mod_dest != (sizeof(CPU_ALIGN) - 1)) {/* If leading octets avail, ... */ + i = (CPU_INT08S)mem_align_mod_dest; + while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */ + (i >= 0)) { /* ... until next CPU_ALIGN word boundary. */ + *pmem_08_dest-- = *pmem_08_src--; + size_rem -= sizeof(CPU_INT08U); + i--; + } + } + + /* See Note #3. */ + pmem_align_dest = ( CPU_ALIGN *)(((CPU_INT08U *)pmem_08_dest - sizeof(CPU_ALIGN)) + 1); + pmem_align_src = (const CPU_ALIGN *)(((CPU_INT08U *)pmem_08_src - sizeof(CPU_ALIGN)) + 1); + while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */ + *pmem_align_dest-- = *pmem_align_src--; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */ + size_rem -= sizeof(CPU_ALIGN); + } + + pmem_08_dest = ( CPU_INT08U *)pmem_align_dest + sizeof(CPU_ALIGN) - 1; + pmem_08_src = (const CPU_INT08U *)pmem_align_src + sizeof(CPU_ALIGN) - 1; + + } + } + + while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */ + *pmem_08_dest-- = *pmem_08_src--; /* ... copy psrc to pdest by octets. */ + size_rem -= sizeof(CPU_INT08U); + } +} + + +/* +********************************************************************************************************* +* Mem_Cmp() +* +* Description : Verifies that ALL data octets in two memory buffers are identical in sequence. +* +* Argument(s) : p1_mem Pointer to first memory buffer. +* +* p2_mem Pointer to second memory buffer. +* +* size Number of data buffer octets to compare (see Note #1). +* +* Return(s) : DEF_YES, if 'size' number of data octets are identical in both memory buffers. +* +* DEF_NO, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) Null compares allowed (i.e. zero-length compares); 'DEF_YES' returned to indicate +* identical null compare. +* +* (2) Many memory buffer comparisons vary ONLY in the least significant octets -- e.g. +* network address buffers. Consequently, memory buffer comparison is more efficient +* if the comparison starts from the end of the memory buffers which will abort sooner +* on dissimilar memory buffers that vary only in the least significant octets. +* +* (3) For best CPU performance, optimized to compare data buffers using 'CPU_ALIGN'-sized +* data words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on +* word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd +* addresses. +* +* (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN' +* address boundary. +* +* Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus +* address values MUST be cast to an appropriately-sized integer value PRIOR to any +* 'mem_align_mod' arithmetic operation. +********************************************************************************************************* +*/ + +CPU_BOOLEAN Mem_Cmp (const void *p1_mem, + const void *p2_mem, + CPU_SIZE_T size) +{ + CPU_SIZE_T size_rem; + CPU_ALIGN *p1_mem_align; + CPU_ALIGN *p2_mem_align; + const CPU_INT08U *p1_mem_08; + const CPU_INT08U *p2_mem_08; + CPU_DATA i; + CPU_DATA mem_align_mod_1; + CPU_DATA mem_align_mod_2; + CPU_BOOLEAN mem_aligned; + CPU_BOOLEAN mem_cmp; + + + if (size < 1) { /* See Note #1. */ + return (DEF_YES); + } + if (p1_mem == (void *)0) { + return (DEF_NO); + } + if (p2_mem == (void *)0) { + return (DEF_NO); + } + + + mem_cmp = DEF_YES; /* Assume mem bufs are identical until cmp fails. */ + size_rem = size; + /* Start @ end of mem bufs (see Note #2). */ + p1_mem_08 = (const CPU_INT08U *)p1_mem + size; + p2_mem_08 = (const CPU_INT08U *)p2_mem + size; + /* See Note #4. */ + mem_align_mod_1 = (CPU_INT08U)((CPU_ADDR)p1_mem_08 % sizeof(CPU_ALIGN)); + mem_align_mod_2 = (CPU_INT08U)((CPU_ADDR)p2_mem_08 % sizeof(CPU_ALIGN)); + + mem_aligned = (mem_align_mod_1 == mem_align_mod_2) ? DEF_YES : DEF_NO; + + if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */ + /* ... optimize cmp for mem buf alignment. */ + if (mem_align_mod_1 != 0u) { /* If trailing octets avail, ... */ + i = mem_align_mod_1; + while ((mem_cmp == DEF_YES) && /* ... cmp mem bufs while identical & ... */ + (size_rem > 0) && /* ... start mem buf cmp with trailing octets ... */ + (i > 0)) { /* ... until next CPU_ALIGN word boundary. */ + p1_mem_08--; + p2_mem_08--; + if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_INT08U); + i--; + } + } + + if (mem_cmp == DEF_YES) { /* If cmp still identical, cmp aligned mem bufs. */ + p1_mem_align = (CPU_ALIGN *)p1_mem_08; /* See Note #3. */ + p2_mem_align = (CPU_ALIGN *)p2_mem_08; + + while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical & ... */ + (size_rem >= sizeof(CPU_ALIGN))) { /* ... mem bufs aligned on CPU_ALIGN word boundaries. */ + p1_mem_align--; + p2_mem_align--; + if (*p1_mem_align != *p2_mem_align) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_ALIGN); + } + + p1_mem_08 = (CPU_INT08U *)p1_mem_align; + p2_mem_08 = (CPU_INT08U *)p2_mem_align; + } + } + + while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical ... */ + (size_rem > 0)) { /* ... for unaligned mem bufs or trailing octets. */ + p1_mem_08--; + p2_mem_08--; + if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */ + mem_cmp = DEF_NO; + } + size_rem -= sizeof(CPU_INT08U); + } + + return (mem_cmp); +} + + +/* +********************************************************************************************************* +* Mem_HeapAlloc() +* +* Description : Allocates a memory block from the heap memory segment. +* +* Argument(s) : size Size of memory block to allocate (in bytes). +* +* align Alignment of memory block to specific word boundary (in bytes). +* +* p_bytes_reqd Optional pointer to a variable to ... : +* +* (a) Return the number of bytes required to successfully +* allocate the memory block, if any error(s); +* (b) Return 0, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap. +* +* ---------------------RETURNED BY Mem_SegAllocInternal()--------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* Return(s) : Pointer to memory block, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) Pointers to variables that return values MUST be initialized PRIOR to all other +* validation or function handling in case of any error(s). +* +* (2) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_SegAlloc(), Mem_SegAllocExt() or Mem_SegAllocHW() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_HeapAlloc (CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_mem; + + + p_mem = Mem_SegAllocInternal(DEF_NULL, + &Mem_SegHeap, + size, + align, + LIB_MEM_CFG_HEAP_PADDING_ALIGN, + p_bytes_reqd, + p_err); + if (*p_err == LIB_MEM_ERR_SEG_OVF) { + *p_err = LIB_MEM_ERR_HEAP_OVF; + } + + return (p_mem); +} +#endif + + +/* +********************************************************************************************************* +* Mem_HeapGetSizeRem() +* +* Description : Gets remaining heap memory size available to allocate. +* +* Argument(s) : align Desired word boundary alignment (in bytes) to return remaining memory size from. +* +* p_err Pointer to variable that will receive the return error code from this function +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* --------------------RETURNED BY Mem_SegRemSizeGet()-------------------- +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : Remaining heap memory size (in bytes), if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_SegRemSizeGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +CPU_SIZE_T Mem_HeapGetSizeRem (CPU_SIZE_T align, + LIB_ERR *p_err) +{ + CPU_SIZE_T rem_size; + + + rem_size = Mem_SegRemSizeGet(&Mem_SegHeap, + align, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return (0u); + } + + return (rem_size); +} +#endif + + +/* +********************************************************************************************************* +* Mem_SegCreate() +* +* Description : Creates a new memory segment to be used for runtime memory allocation. +* +* Argument(s) : p_name Pointer to segment name. +* +* p_seg Pointer to segment data. Must be allocated by caller. +* +* seg_base_addr Address of segment's first byte. +* +* size Total size of segment, in bytes. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size specified. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid padding alignment. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* -------------------RETURNED BY Mem_SegOverlapChkCritical()------------------- +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) New segments are checked for overlap with existing segments. A critical section needs +* to be maintained during the whole list search and add procedure to prevent a reentrant +* call from creating another segment overlapping with the one being added. +********************************************************************************************************* +*/ + +void Mem_SegCreate (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + CPU_SIZE_T padding_align, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (size < 1u) { /* Chk for invalid sized seg. */ + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + /* Chk for addr space ovf. */ + if (seg_base_addr + (size - 1u) < seg_base_addr) { + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + + if ((padding_align != LIB_MEM_PADDING_ALIGN_NONE) && + (MATH_IS_PWR2(padding_align) != DEF_YES)) { + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \ + (LIB_MEM_CFG_HEAP_SIZE > 0u) + (void)Mem_SegOverlapChkCritical(seg_base_addr, /* Chk for overlap. */ + size, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } +#endif + + Mem_SegCreateCritical(p_name, /* Create seg. */ + p_seg, + seg_base_addr, + padding_align, + size); + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_SegClr() +* +* Description : Clears a memory segment. +* +* Argument(s) : p_seg Pointer to segment data. Must be allocated by caller. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function must be used with extreme caution. It must only be called on memory +* segments that are no longer used. +* +* (2) This function is disabled when debug mode is enabled to avoid heap memory leaks. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_DISABLED) +void Mem_SegClr (MEM_SEG *p_seg, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + p_seg->AddrNext = p_seg->AddrBase; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_SegRemSizeGet() +* +* Description : Gets free space of memory segment. +* +* Argument(s) : p_seg Pointer to segment data. +* +* align Alignment in bytes to assume for calculation of free space. +* +* p_seg_info Pointer to structure that will receive further segment info data (used size, +* total size, base address and next allocation address). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : Memory segment remaining size in bytes, if successful. +* 0, otherwise or if memory segment empty. +* +* Caller(s) : Application, +* Mem_HeapGetSizeRem(), +* Mem_OutputUsage(). +* +* Note(s) : None. +********************************************************************************************************* +*/ + +CPU_SIZE_T Mem_SegRemSizeGet (MEM_SEG *p_seg, + CPU_SIZE_T align, + MEM_SEG_INFO *p_seg_info, + LIB_ERR *p_err) +{ + CPU_SIZE_T rem_size; + CPU_SIZE_T total_size; + CPU_SIZE_T used_size; + CPU_ADDR next_addr_align; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(0); + } + + if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk for invalid align val. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return (0u); + } +#endif + + if (p_seg == DEF_NULL) { /* Dflt to heap in case p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); +#endif + } + + CPU_CRITICAL_ENTER(); /* Calc seg stats. */ + next_addr_align = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, align); + CPU_CRITICAL_EXIT(); + + total_size = (p_seg->AddrEnd - p_seg->AddrBase) + 1u; + used_size = p_seg->AddrNext - p_seg->AddrBase; + + if (next_addr_align > p_seg->AddrEnd){ + next_addr_align = 0u; + rem_size = 0u; + } else { + rem_size = total_size - (next_addr_align - p_seg->AddrBase); + } + + if (p_seg_info != DEF_NULL) { + p_seg_info->TotalSize = total_size; + p_seg_info->UsedSize = used_size; + p_seg_info->AddrBase = p_seg->AddrBase; + p_seg_info->AddrNextAlloc = next_addr_align; + } + + *p_err = LIB_MEM_ERR_NONE; + + return (rem_size); +} + + +/* +********************************************************************************************************* +* Mem_SegAlloc() +* +* Description : Allocates memory from specified segment. Returned memory block will be aligned on a CPU +* word boundary. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) The memory block returned by this function will be aligned on a word boundary. In +* order to specify a specific alignment value, use either Mem_SegAllocExt() or +* Mem_SegAllocHW(). +********************************************************************************************************* +*/ + +void *Mem_SegAlloc (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocExt() +* +* Description : Allocates memory from specified memory segment. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_SegAllocExt (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + align, + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocHW() +* +* Description : Allocates memory from specified segment. The returned buffer will be padded in function +* of memory segment's properties. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_SegAllocHW (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + + + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); +#endif + } + + p_blk = Mem_SegAllocInternal(p_name, + p_seg, + size, + align, + p_seg->PaddingAlign, + p_bytes_reqd, + p_err); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_PoolCreate() +* +* Description : (1) Creates a memory pool : +* +* (a) Create memory pool from heap or dedicated memory +* (b) Allocate memory pool memory blocks +* (c) Configure memory pool +* +* +* Argument(s) : p_pool Pointer to a memory pool structure to create (see Note #1). +* +* p_mem_base Memory pool segment base address : +* +* (a) Null address Memory pool allocated from general-purpose heap. +* (b) Non-null address Memory pool allocated from dedicated memory +* specified by its base address. +* +* mem_size Size of memory pool segment (in bytes). +* +* blk_nbr Number of memory pool blocks to create. +* +* blk_size Size of memory pool blocks to create (in bytes). +* +* blk_align Alignment of memory pool blocks to specific word boundary (in bytes). +* +* p_bytes_reqd Optional pointer to a variable to ... : +* +* (a) Return the number of bytes required to successfully +* allocate the memory pool, if any error(s); +* (b) Return 0, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Pointer to memory pool is null. +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid block alignment requested. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid number of blocks specified. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid block size specified. +* LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size. +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap. +* +* ---------------RETURNED BY Mem_SegOverlapChkCritical()---------------- +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* +* -----------------RETURNED BY Mem_SegAllocExtCritical()----------------- +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* -----------------------RETURNED BY Mem_PoolClr()----------------------- +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolCreate() or Mem_DynPoolCreateHW() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolCreate (MEM_POOL *p_pool, + void *p_mem_base, + CPU_SIZE_T mem_size, + MEM_POOL_BLK_QTY blk_nbr, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + MEM_SEG *p_seg; + void *p_pool_mem; + CPU_SIZE_T pool_size; + CPU_SIZE_T blk_size_align; + CPU_ADDR pool_addr_end; + MEM_POOL_BLK_QTY blk_ix; + CPU_INT08U *p_blk; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* --------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + /* ------------- VALIDATE MEM POOL CREATE ------------- */ + if (p_pool == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_mem_base != DEF_NULL) { + if (mem_size < 1u) { + *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE; + return; + } + } + + if (blk_nbr < 1u) { + *p_err = LIB_MEM_ERR_INVALID_BLK_NBR; + return; + } + + if (blk_size < 1u) { + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return; + } + + if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk that req alignment is a pwr of 2. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN; + return; + } +#endif + + Mem_PoolClr(p_pool, p_err); /* Init mem pool. */ + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* -------- DETERMINE AND/OR ALLOC SEG TO USE --------- */ + if (p_mem_base == DEF_NULL) { /* Use heap seg. */ + p_seg = &Mem_SegHeap; + } else { /* Use other seg. */ + CPU_CRITICAL_ENTER(); + p_seg = Mem_SegOverlapChkCritical((CPU_ADDR)p_mem_base, + mem_size, + p_err); + switch (*p_err) { + case LIB_MEM_ERR_INVALID_SEG_EXISTS: /* Seg already exists. */ + break; + + case LIB_MEM_ERR_NONE: /* Seg must be created. */ + p_seg = (MEM_SEG *)Mem_SegAllocExtCritical(&Mem_SegHeap, + sizeof(MEM_SEG), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */ + Mem_SegAllocTrackCritical("Unknown segment data", + &Mem_SegHeap, + sizeof(MEM_SEG), + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } +#endif + + Mem_SegCreateCritical( DEF_NULL, + p_seg, + (CPU_ADDR)p_mem_base, + LIB_MEM_PADDING_ALIGN_NONE, + mem_size); + break; + + + case LIB_MEM_ERR_INVALID_SEG_OVERLAP: + default: + CPU_CRITICAL_EXIT(); + return; /* Prevent 'break NOT reachable' compiler warning. */ + } + + CPU_CRITICAL_EXIT(); + } + + + /* ---------------- ALLOC MEM FOR POOL ---------------- */ + /* Calc blk size with align. */ + blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align); + pool_size = blk_size_align * blk_nbr; /* Calc required size for pool. */ + + /* Alloc mem for pool. */ + p_pool_mem = (void *)Mem_SegAllocInternal("Unnamed static pool", + p_seg, + pool_size, + blk_align, + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* ------------ ALLOC MEM FOR FREE BLK TBL ------------ */ + p_pool->BlkFreeTbl = (void **)Mem_SegAllocInternal("Unnamed static pool free blk tbl", + &Mem_SegHeap, + blk_nbr * sizeof(void *), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* ------------------ INIT BLK LIST ------------------- */ + p_blk = (CPU_INT08U *)p_pool_mem; + for (blk_ix = 0; blk_ix < blk_nbr; blk_ix++) { + p_pool->BlkFreeTbl[blk_ix] = p_blk; + p_blk += blk_size_align; + } + + + /* ------------------ INIT POOL DATA ------------------ */ + pool_addr_end = (CPU_ADDR)p_pool_mem + (pool_size - 1u); + p_pool->PoolAddrStart = p_pool_mem; + p_pool->PoolAddrEnd = (void *)pool_addr_end; + p_pool->BlkNbr = blk_nbr; + p_pool->BlkSize = blk_size_align; + p_pool->BlkFreeTblIx = blk_nbr; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolClr() +* +* Description : Clears a memory pool (see Note #1). +* +* Argument(s) : p_pool Pointer to a memory pool structure to clear (see Note #2). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : none. +* +* Caller(s) : Application, +* Mem_PoolCreate(). +* +* Note(s) : (1) (a) Mem_PoolClr() ONLY clears a memory pool structure's variables & should ONLY be +* called to initialize a memory pool structure prior to calling Mem_PoolCreate(). +* +* (b) Mem_PoolClr() does NOT deallocate memory from the memory pool or deallocate the +* memory pool itself & MUST NOT be called after calling Mem_PoolCreate() since +* this will likely corrupt the memory pool management. +* +* (2) Assumes 'p_pool' points to a valid memory pool (if non-NULL). +* +* (3) This function is DEPRECATED and will be removed in a future version of this product. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolClr (MEM_POOL *p_pool, + LIB_ERR *p_err) +{ +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + /* -------------- VALIDATE MEM POOL PTR --------------- */ + if (p_pool == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + p_pool->PoolAddrStart = DEF_NULL; + p_pool->PoolAddrEnd = DEF_NULL; + p_pool->BlkSize = 0u; + p_pool->BlkNbr = 0u; + p_pool->BlkFreeTbl = DEF_NULL; + p_pool->BlkFreeTblIx = 0u; + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkGet() +* +* Description : Gets a memory block from memory pool. +* +* Argument(s) : p_pool Pointer to memory pool to get memory block from. +* +* size Size of requested memory (in bytes). +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid memory pool block size requested. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* LIB_MEM_ERR_POOL_EMPTY NO memory blocks available in memory pool. +* +* Return(s) : Pointer to memory block, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_PoolBlkGet (MEM_POOL *p_pool, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + CPU_INT08U *p_blk; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL GET --------------- */ + if (p_err == DEF_NULL) { /* Validate err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (p_pool == DEF_NULL) { /* Validate pool ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); + } + + if (size < 1u) { /* Validate req'd size as non-NULL. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return (DEF_NULL); + } + + if (size > p_pool->BlkSize) { /* Validate req'd size <= mem pool blk size. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return (DEF_NULL); + } +#else + (void)size; /* Prevent possible 'variable unused' warning. */ +#endif + + + /* -------------- GET MEM BLK FROM POOL --------------- */ + p_blk = DEF_NULL; + CPU_CRITICAL_ENTER(); + if (p_pool->BlkFreeTblIx > 0u) { + p_pool->BlkFreeTblIx -= 1u; + p_blk = (CPU_INT08U *)p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx]; + p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = DEF_NULL; + } + CPU_CRITICAL_EXIT(); + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_POOL_EMPTY; + } else { + *p_err = LIB_MEM_ERR_NONE; + } + + return (p_blk); +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkFree() +* +* Description : Free a memory block to memory pool. +* +* Argument(s) : p_pool Pointer to memory pool to free memory block. +* +* p_blk Pointer to memory block address to free. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool'/'p_blk' passed +* a NULL pointer. +* LIB_MEM_ERR_INVALID_BLK_ADDR Invalid memory block address. +* LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL Memory block address already +* in memory pool. +* LIB_MEM_ERR_POOL_FULL Pool is full. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkFree() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void Mem_PoolBlkFree (MEM_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err) +{ +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + CPU_SIZE_T tbl_ix; + CPU_BOOLEAN addr_valid; +#endif + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL FREE -------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Validate mem ptrs. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + addr_valid = Mem_PoolBlkIsValidAddr(p_pool, p_blk); /* Validate mem blk as valid pool blk addr. */ + if (addr_valid != DEF_OK) { + *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR; + return; + } + + CPU_CRITICAL_ENTER(); /* Make sure blk isn't already in free list. */ + for (tbl_ix = 0u; tbl_ix < p_pool->BlkNbr; tbl_ix++) { + if (p_pool->BlkFreeTbl[tbl_ix] == p_blk) { + CPU_CRITICAL_EXIT(); + *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL; + return; + } + } +#else /* Double-free possibility if not in critical section. */ + CPU_CRITICAL_ENTER(); +#endif + /* --------------- FREE MEM BLK TO POOL --------------- */ + if (p_pool->BlkFreeTblIx >= p_pool->BlkNbr) { + CPU_CRITICAL_EXIT(); + *p_err = LIB_MEM_ERR_POOL_FULL; + return; + } + + p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = p_blk; + p_pool->BlkFreeTblIx += 1u; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +* Mem_PoolBlkGetNbrAvail() +* +* Description : Get memory pool's remaining number of blocks available to allocate. +* +* Argument(s) : p_pool Pointer to a memory pool structure. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer. +* +* Return(s) : Remaining memory pool blocks, if NO error(s). +* +* 0, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +* Mem_DynPoolBlkNbrAvailGet() should be used instead. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +MEM_POOL_BLK_QTY Mem_PoolBlkGetNbrAvail (MEM_POOL *p_pool, + LIB_ERR *p_err) +{ + CPU_SIZE_T nbr_avail; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + /* --------------- VALIDATE RTN ERR PTR --------------- */ + if (p_err == DEF_NULL) { + CPU_SW_EXCEPTION(0u); + } + /* ---------------- VALIDATE MEM POOL ----------------- */ + if (p_pool == DEF_NULL) { /* Validate mem ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + nbr_avail = p_pool->BlkFreeTblIx; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + + return (nbr_avail); +} +#endif + + +/* +********************************************************************************************************* +* Mem_DynPoolCreate() +* +* Description : Creates a dynamic memory pool. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. Will be allocated from +* general-purpose heap if null. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* --------------------RETURNED BY Mem_DynPoolCreateInternal()------------------- +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +void Mem_DynPoolCreate (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return; +#endif + } + + Mem_DynPoolCreateInternal(p_name, + p_pool, + p_seg, + blk_size, + blk_align, + LIB_MEM_PADDING_ALIGN_NONE, + blk_qty_init, + blk_qty_max, + p_err); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolCreateHW() +* +* Description : Creates a dynamic memory pool. Memory blocks will be padded according to memory segment's +* properties. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. Will allocate from +* general-purpose heap if null. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* +* -------------------RETURNED BY Mem_DynPoolCreateInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +void Mem_DynPoolCreateHW (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_seg = &Mem_SegHeap; +#else + *p_err = LIB_MEM_ERR_NULL_PTR; + return; +#endif + } + + Mem_DynPoolCreateInternal(p_name, + p_pool, + p_seg, + blk_size, + blk_align, + p_seg->PaddingAlign, + blk_qty_init, + blk_qty_max, + p_err); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkGet() +* +* Description : Gets a memory block from specified pool, growing it if needed. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* LIB_MEM_ERR_POOL_EMPTY Pools is empty. +* +* ----------------------RETURNED BY Mem_SegAllocInternal()----------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void *Mem_DynPoolBlkGet (MEM_DYN_POOL *p_pool, + LIB_ERR *p_err) +{ + void *p_blk; + const CPU_CHAR *p_pool_name; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (DEF_NULL); + } +#endif + + /* Ensure pool is not empty if qty is limited. */ + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { + CPU_CRITICAL_ENTER(); + if (p_pool->BlkAllocCnt >= p_pool->BlkQtyMax) { + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_POOL_EMPTY; + return (DEF_NULL); + } + + p_pool->BlkAllocCnt++; + CPU_CRITICAL_EXIT(); + } + + /* --------------- ALLOC FROM FREE LIST --------------- */ + CPU_CRITICAL_ENTER(); + if (p_pool->BlkFreePtr != DEF_NULL) { + p_blk = p_pool->BlkFreePtr; + p_pool->BlkFreePtr = *((void **)p_blk); + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + + return (p_blk); + } + CPU_CRITICAL_EXIT(); + + /* ------------------ ALLOC NEW BLK ------------------- */ +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_pool_name = p_pool->NamePtr; +#else + p_pool_name = DEF_NULL; +#endif + p_blk = Mem_SegAllocInternal(p_pool_name, + p_pool->PoolSegPtr, + p_pool->BlkSize, + p_pool->BlkAlign, + p_pool->BlkPaddingAlign, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { + p_pool->BlkAllocCnt--; + } + return (DEF_NULL); + } + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkFree() +* +* Description : Frees memory block, making it available for future use. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_blk Pointer to first byte of memory block. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'p_pool' or 'p_blk' pointer passed is NULL. +* LIB_MEM_ERR_POOL_FULL Pool is full. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +void Mem_DynPoolBlkFree (MEM_DYN_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (p_blk == DEF_NULL) { + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { /* Ensure pool is not full. */ + CPU_CRITICAL_ENTER(); + if (p_pool->BlkAllocCnt == 0u) { + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_POOL_FULL; + return; + } + + p_pool->BlkAllocCnt--; + CPU_CRITICAL_EXIT(); + } + + CPU_CRITICAL_ENTER(); + *((void **)p_blk) = p_pool->BlkFreePtr; + p_pool->BlkFreePtr = p_blk; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_DynPoolBlkNbrAvailGet() +* +* Description : Gets number of available blocks in dynamic memory pool. This call will fail with a +* dynamic memory pool for which no limit was set at creation. +* +* Argument(s) : p_pool Pointer to pool data. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'p_pool' pointer passed is NULL. +* LIB_MEM_ERR_POOL_UNLIMITED Pool has no specified limit. +* +* Return(s) : Number of blocks available in dynamic memory pool, if successful. +* +* 0, if pool is empty or if an error occurred. +* +* Caller(s) : Application. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +CPU_SIZE_T Mem_DynPoolBlkNbrAvailGet (MEM_DYN_POOL *p_pool, + LIB_ERR *p_err) +{ + CPU_SIZE_T blk_nbr_avail; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(0); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return (0u); + } +#endif + + if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { + CPU_CRITICAL_ENTER(); + blk_nbr_avail = p_pool->BlkQtyMax - p_pool->BlkAllocCnt; + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; + } else { + blk_nbr_avail = 0u; + *p_err = LIB_MEM_ERR_POOL_UNLIMITED; + } + + return (blk_nbr_avail); +} + + +/* +********************************************************************************************************* +* Mem_OutputUsage() +* +* Description : Outputs memory usage report through 'out_fnct'. +* +* Argument(s) : out_fnct Pointer to output function. +* +* print_details DEF_YES, if the size of each allocation should be printed. +* DEF_NO, otherwise. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_NONE Operation was successful. +* LIB_MEM_ERR_NULL_PTR 'out_fnct' pointer passed is NULL. +* +* ---------------------RETURNED BY Mem_SegRemSizeGet()-------------------- +* LIB_MEM_ERR_NULL_PTR Segment data pointer NULL. +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment. +* +* Return(s) : None. +* +* Caller(s) : Application. +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +void Mem_OutputUsage(void (*out_fnct) (CPU_CHAR *), + LIB_ERR *p_err) +{ + CPU_CHAR str[DEF_INT_32U_NBR_DIG_MAX]; + MEM_SEG *p_seg; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (out_fnct == DEF_NULL) { /* Chk for NULL out fnct ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } +#endif + + out_fnct((CPU_CHAR *)"---------------- Memory allocation info ----------------\r\n"); + out_fnct((CPU_CHAR *)"| Type | Size | Free size | Name\r\n"); + out_fnct((CPU_CHAR *)"|---------|------------|------------|-------------------\r\n"); + + CPU_CRITICAL_ENTER(); + p_seg = Mem_SegHeadPtr; + while (p_seg != DEF_NULL) { + CPU_SIZE_T rem_size; + MEM_SEG_INFO seg_info; + MEM_ALLOC_INFO *p_alloc; + + + rem_size = Mem_SegRemSizeGet(p_seg, 1u, &seg_info, p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + out_fnct((CPU_CHAR *)"| Section | "); + + (void)Str_FmtNbr_Int32U(seg_info.TotalSize, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct((CPU_CHAR *)" | "); + + (void)Str_FmtNbr_Int32U(rem_size, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct((CPU_CHAR *)" | "); + out_fnct((p_seg->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_seg->NamePtr : (CPU_CHAR *)"Unknown"); + out_fnct((CPU_CHAR *)"\r\n"); + + p_alloc = p_seg->AllocInfoHeadPtr; + while (p_alloc != DEF_NULL) { + out_fnct((CPU_CHAR *)"| -> Obj | "); + + (void)Str_FmtNbr_Int32U(p_alloc->Size, + 10u, + DEF_NBR_BASE_DEC, + ' ', + DEF_NO, + DEF_YES, + &str[0u]); + + out_fnct(str); + out_fnct((CPU_CHAR *)" | | "); + + out_fnct((p_alloc->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_alloc->NamePtr : (CPU_CHAR *)"Unknown"); + out_fnct((CPU_CHAR *)"\r\n"); + + p_alloc = p_alloc->NextPtr; + } + + p_seg = p_seg->NextPtr; + } + CPU_CRITICAL_EXIT(); + + *p_err = LIB_MEM_ERR_NONE; +} +#endif + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Mem_SegCreateCritical() +* +* Description : Creates a new memory segment to be used for runtime memory allocation or dynamic pools. +* +* Argument(s) : p_name Pointer to segment name. +* +* p_seg Pointer to segment data. Must be allocated by caller. +* ----- Argument validated by caller. +* +* seg_base_addr Segment's first byte address. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer +* from this memory segment. MUST be a power of 2. +* LIB_MEM_PADDING_ALIGN_NONE means no padding. +* ------------- Argument validated by caller. +* +* size Total size of segment, in bytes. +* ---- Argument validated by caller. +* +* Return(s) : Pointer to segment data, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegCreate(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +static void Mem_SegCreateCritical(const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T padding_align, + CPU_SIZE_T size) +{ + p_seg->AddrBase = seg_base_addr; + p_seg->AddrEnd = (seg_base_addr + (size - 1u)); + p_seg->AddrNext = seg_base_addr; + p_seg->NextPtr = Mem_SegHeadPtr; + p_seg->PaddingAlign = padding_align; + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_seg->NamePtr = p_name; + p_seg->AllocInfoHeadPtr = DEF_NULL; +#else + (void)p_name; +#endif + + Mem_SegHeadPtr = p_seg; +} + + +/* +********************************************************************************************************* +* Mem_SegOverlapChkCritical() +* +* Description : Checks if existing memory segment exists or overlaps with specified memory area. +* +* Argument(s) : seg_base_addr Address of first byte of memory area. +* +* size Size of memory area, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment. +* LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists. +* +* Return(s) : Pointer to memory segment that overlaps. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegCreate(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +static MEM_SEG *Mem_SegOverlapChkCritical (CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + MEM_SEG *p_seg_chk; + CPU_ADDR seg_new_end; + CPU_ADDR seg_chk_start; + CPU_ADDR seg_chk_end; + + + seg_new_end = seg_base_addr + (size - 1u); + p_seg_chk = Mem_SegHeadPtr; + + while (p_seg_chk != DEF_NULL) { + seg_chk_start = (CPU_ADDR)p_seg_chk->AddrBase; + seg_chk_end = (CPU_ADDR)p_seg_chk->AddrEnd; + + if ((seg_base_addr == seg_chk_start) && (seg_new_end == seg_chk_end)) { + *p_err = LIB_MEM_ERR_INVALID_SEG_EXISTS; + return (p_seg_chk); + } else if (((seg_base_addr >= seg_chk_start) && (seg_base_addr <= seg_chk_end)) || + ((seg_base_addr <= seg_chk_start) && (seg_new_end >= seg_chk_start))) { + *p_err = LIB_MEM_ERR_INVALID_SEG_OVERLAP; + return (p_seg_chk); + } else { + /* Empty Else Statement */ + } + + p_seg_chk = p_seg_chk->NextPtr; + } + + *p_err = LIB_MEM_ERR_NONE; + + return (DEF_NULL); +} +#endif + + +/* +********************************************************************************************************* +* Mem_SegAllocInternal() +* +* Description : Allocates memory from specified segment. +* +* Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL. +* +* p_seg Pointer to segment from which to allocate memory. +* ----- Argument validated by caller. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* +* ------------------RETURNED BY Mem_SegAllocExtCritical()------------------ +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_DynPoolBlkGet(), +* Mem_DynPoolCreateInternal(), +* Mem_HeapAlloc(), +* Mem_PoolCreate(), +* Mem_SegAlloc(), +* Mem_SegAllocExt(), +* Mem_SegAllocHW(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +static void *Mem_SegAllocInternal (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + void *p_blk; + CPU_SR_ALLOC(); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for null err ptr. */ + CPU_SW_EXCEPTION(DEF_NULL); + } + + if (size < 1u) { /* Chk for invalid sized mem req. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_SIZE; + return (DEF_NULL); + } + + if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk that align is a pwr of 2. */ + *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN; + return (DEF_NULL); + } +#endif + + CPU_CRITICAL_ENTER(); + p_blk = Mem_SegAllocExtCritical(p_seg, + size, + align, + padding_align, + p_bytes_reqd, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return (DEF_NULL); + } + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */ + Mem_SegAllocTrackCritical(p_name, + p_seg, + size, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return (DEF_NULL); + } +#else + (void)p_name; +#endif + CPU_CRITICAL_EXIT(); + + return (p_blk); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocExtCritical() +* +* Description : Allocates memory from specified segment. +* +* Argument(s) : p_seg Pointer to segment from which to allocate memory. +* +* size Size of memory block to allocate, in bytes. +* +* align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* padding_align Padding alignment, in bytes, that will be added to any allocated buffer from +* this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for +* the allocation to succeed. Set to DEF_NULL to skip calculation. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : Pointer to allocated memory block, if successful. +* +* DEF_NULL, otherwise. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegAllocInternal(), +* Mem_SegAllocTrackCritical(). +* +* Note(s) : (1) This function MUST be called within a CRITICAL_SECTION. +********************************************************************************************************* +*/ + +static void *Mem_SegAllocExtCritical (MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T padding_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err) +{ + CPU_ADDR blk_addr; + CPU_ADDR addr_next; + CPU_SIZE_T size_rem_seg; + CPU_SIZE_T size_tot_blk; + CPU_SIZE_T blk_align = DEF_MAX(align, padding_align); + + + blk_addr = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, /* Compute align'ed blk addr. */ + blk_align); + addr_next = MATH_ROUND_INC_UP_PWR2(blk_addr + size, /* Compute addr of next alloc. */ + padding_align); + size_rem_seg = (p_seg->AddrEnd - p_seg->AddrNext) + 1u; + size_tot_blk = addr_next - p_seg->AddrNext; /* Compute tot blk size including align and padding. */ + if (size_rem_seg < size_tot_blk) { /* If seg doesn't have enough space ... */ + if (p_bytes_reqd != DEF_NULL) { /* ... calc nbr of req'd bytes. */ + *p_bytes_reqd = size_tot_blk - size_rem_seg; + } + + *p_err = LIB_MEM_ERR_SEG_OVF; + return (DEF_NULL); + } + + p_seg->AddrNext = addr_next; + + *p_err = LIB_MEM_ERR_NONE; + + return ((void *)blk_addr); +} + + +/* +********************************************************************************************************* +* Mem_SegAllocTrackCritical() +* +* Description : Tracks segment allocation, adding the 'size' of the allocation under the 'p_name' entry. +* +* Argument(s) : p_name Pointer to the name of the object. This string is not copied and its memory should +* remain accessible at all times. +* +* p_seg Pointer to segment data. +* +* size Allocation size, in bytes. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap +* +* --------------RETURNED BY Mem_SegAllocExtCritical()--------------- +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : none. +* +* Caller(s) : Mem_PoolCreate(), +* Mem_SegAllocInternal(). +* +* Note(s) : none. +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +static void Mem_SegAllocTrackCritical (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err) +{ + MEM_ALLOC_INFO *p_alloc; + + + /* ------- UPDATE ALLOC INFO LIST, IF POSSIBLE -------- */ + p_alloc = p_seg->AllocInfoHeadPtr; + while (p_alloc != DEF_NULL) { + if (p_alloc->NamePtr == p_name) { + p_alloc->Size += size; + *p_err = LIB_MEM_ERR_NONE; + return; + } + + p_alloc = p_alloc->NextPtr; + } + + /* --------- ADD NEW ALLOC INFO ENTRY IN LIST --------- */ + p_alloc = (MEM_ALLOC_INFO *)Mem_SegAllocExtCritical(&Mem_SegHeap, /* Alloc new alloc info struct on heap. */ + sizeof(MEM_ALLOC_INFO), + sizeof(CPU_ALIGN), + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + p_alloc->NamePtr = p_name; /* Populate alloc info. */ + p_alloc->Size = size; + + p_alloc->NextPtr = p_seg->AllocInfoHeadPtr; /* Prepend new item in list. */ + p_seg->AllocInfoHeadPtr = p_alloc; +} +#endif + + +/* +********************************************************************************************************* +* Mem_DynPoolCreateInternal() +* +* Description : Creates a dynamic memory pool. +* +* Argument(s) : p_name Pointer to pool name. +* +* p_pool Pointer to pool data. +* +* p_seg Pointer to segment from which to allocate memory. +* +* blk_size Size of memory block to allocate from pool, in bytes. See Note #1. +* +* blk_align Required alignment of memory block, in bytes. MUST be a power of 2. +* +* blk_padding_align Block's padding alignment, in bytes, that will be added at the end +* of block's buffer. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE +* means no padding. +* +* blk_qty_init Initial number of elements to be allocated in pool. +* +* blk_qty_max Maximum number of elements that can be allocated from this pool. Set to +* LIB_MEM_BLK_QTY_UNLIMITED if no limit. +* +* p_err Pointer to variable that will receive the return error code from this function : +* +* LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment. +* LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size. +* LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max. +* LIB_MEM_ERR_NULL_PTR Pool data pointer NULL. +* +* ------------------RETURNED BY Mem_SegAllocInternal()------------------- +* LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested. +* LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified. +* LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL. +* LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment. +* +* Return(s) : None. +* +* Caller(s) : Mem_DynPoolCreate(), +* Mem_DynPoolCreateHW(). +* +* Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free +* block is stored in the block itself (only when free/unused). +********************************************************************************************************* +*/ + +static void Mem_DynPoolCreateInternal (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_padding_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err) +{ + CPU_INT08U *p_blks = DEF_NULL; + CPU_SIZE_T blk_size_align; + CPU_SIZE_T blk_align_worst = DEF_MAX(blk_align, blk_padding_align); + + +#if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) + if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */ + CPU_SW_EXCEPTION(;); + } + + if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */ + *p_err = LIB_MEM_ERR_NULL_PTR; + return; + } + + if (blk_size < 1u) { /* Chk for inv blk size. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE; + return; + } + + if ((blk_qty_max != LIB_MEM_BLK_QTY_UNLIMITED) && /* Chk for invalid blk qty. */ + (blk_qty_init > blk_qty_max)) { + *p_err = LIB_MEM_ERR_INVALID_BLK_NBR; + return; + } + + if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk for illegal align spec. */ + *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN; + return; + } +#endif + + /* Calc blk size with align. */ + if (blk_size < sizeof(void *)) { /* If size if smaller than ptr ... */ + /* ... inc size to ptr size. */ + blk_size_align = MATH_ROUND_INC_UP_PWR2(sizeof(void *), blk_align_worst); + } else { + blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align_worst); + } + + if (blk_qty_init != 0u) { /* Alloc init blks. */ + CPU_SIZE_T i; + p_blks = (CPU_INT08U *)Mem_SegAllocInternal(p_name, + p_seg, + blk_size_align * blk_qty_init, + DEF_MAX(blk_align, sizeof(void *)), + LIB_MEM_PADDING_ALIGN_NONE, + DEF_NULL, + p_err); + if (*p_err != LIB_MEM_ERR_NONE) { + return; + } + + /* ----------------- CREATE POOL DATA ----------------- */ + /* Init free list. */ + p_pool->BlkFreePtr = (void *)p_blks; + for (i = 0u; i < blk_qty_init - 1u; i++) { + *((void **)p_blks) = p_blks + blk_size_align; + p_blks += blk_size_align; + } + *((void **)p_blks) = DEF_NULL; + } else { + p_pool->BlkFreePtr = DEF_NULL; + } + +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) + p_pool->PoolSegPtr = ((p_seg != DEF_NULL) ? p_seg : &Mem_SegHeap); +#else + p_pool->PoolSegPtr = p_seg; +#endif + p_pool->BlkSize = blk_size; + p_pool->BlkAlign = blk_align_worst; + p_pool->BlkPaddingAlign = blk_padding_align; + p_pool->BlkQtyMax = blk_qty_max; + p_pool->BlkAllocCnt = 0u; + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + p_pool->NamePtr = p_name; +#endif + + *p_err = LIB_MEM_ERR_NONE; +} + + +/* +********************************************************************************************************* +* Mem_PoolBlkIsValidAddr() +* +* Description : Calculates if a given memory block address is valid for the memory pool. +* +* Argument(s) : p_pool Pointer to memory pool structure to validate memory block address. +* ------ Argument validated by caller. +* +* p_mem Pointer to memory block address to validate. +* ----- Argument validated by caller. +* +* Return(s) : DEF_YES, if valid memory pool block address. +* +* DEF_NO, otherwise. +* +* Caller(s) : Mem_PoolBlkFree(). +* +* Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product. +********************************************************************************************************* +*/ + +#if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \ + (LIB_MEM_CFG_HEAP_SIZE > 0u)) +static CPU_BOOLEAN Mem_PoolBlkIsValidAddr (MEM_POOL *p_pool, + void *p_mem) +{ + CPU_ADDR pool_offset; + + + if ((p_mem < p_pool->PoolAddrStart) || + (p_mem > p_pool->PoolAddrEnd)) { + return (DEF_FALSE); + } + + pool_offset = (CPU_ADDR)p_mem - (CPU_ADDR)p_pool->PoolAddrStart; + if (pool_offset % p_pool->BlkSize != 0u) { + return (DEF_FALSE); + } else { + return (DEF_TRUE); + } +} +#endif diff --git a/rtos/uC-LIB/lib_mem.h b/rtos/uC-LIB/lib_mem.h new file mode 100644 index 00000000..fcd87e40 --- /dev/null +++ b/rtos/uC-LIB/lib_mem.h @@ -0,0 +1,1438 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* STANDARD MEMORY OPERATIONS +* +* Filename : lib_mem.h +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +* (2) Assumes the following versions (or more recent) of software modules are included in +* the project build : +* +* (a) uC/CPU V1.27 +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This memory library header file is protected from multiple pre-processor inclusion through +* use of the memory library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_MODULE_PRESENT /* See Note #1. */ +#define LIB_MEM_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_cfg.h +* +* (b) \\lib_*.* +* +* where +* directory path for Your Product's Application +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) '\\' directory See Note #1b +* +* (c) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +********************************************************************************************************* +*/ + +#include +#include + +#include +#include + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_MEM_MODULE +#define LIB_MEM_EXT +#else +#define LIB_MEM_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define LIB_MEM_PADDING_ALIGN_NONE 1u + +#define LIB_MEM_BLK_QTY_UNLIMITED 0u + + +/* +********************************************************************************************************* +* DEFAULT CONFIGURATION +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY LIBRARY ARGUMENT CHECK CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_ARG_CHK_EXT_EN to enable/disable the memory library suite external +* argument check feature : +* +* (a) When ENABLED, arguments received from any port interface provided by the developer +* or application are checked/validated. +* +* (b) When DISABLED, NO arguments received from any port interface provided by the developer +* or application are checked/validated. +********************************************************************************************************* +*/ + + /* Cfg external argument check feature (see Note #1) : */ +#ifndef LIB_MEM_CFG_ARG_CHK_EXT_EN +#define LIB_MEM_CFG_ARG_CHK_EXT_EN DEF_DISABLED + /* DEF_DISABLED Argument check DISABLED */ + /* DEF_ENABLED Argument check ENABLED */ +#endif + + +/* +********************************************************************************************************* +* MEMORY LIBRARY ASSEMBLY OPTIMIZATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_OPTIMIZE_ASM_EN to enable/disable assembly-optimized memory +* functions. +********************************************************************************************************* +*/ + + /* Cfg assembly-optimized function(s) [see Note #1] : */ +#ifndef LIB_MEM_CFG_OPTIMIZE_ASM_EN +#define LIB_MEM_CFG_OPTIMIZE_ASM_EN DEF_DISABLED + /* DEF_DISABLED Assembly-optimized fnct(s) DISABLED */ + /* DEF_ENABLED Assembly-optimized fnct(s) ENABLED */ +#endif + + +/* +********************************************************************************************************* +* MEMORY ALLOCATION DEBUG INFORMATION CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_DBG_INFO_EN to enable/disable debug information associated to each +* segment allocation. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_DBG_INFO_EN +#define LIB_MEM_CFG_DBG_INFO_EN DEF_DISABLED +#endif + + +/* +********************************************************************************************************* +* HEAP PADDING ALIGN CONFIGURATION +* +* Note(s) : (1) Configure LIB_MEM_CFG_HEAP_PADDING_ALIGN to set the padding alignment of any buffer +* allocated from the heap. +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_HEAP_PADDING_ALIGN +#define LIB_MEM_CFG_HEAP_PADDING_ALIGN LIB_MEM_PADDING_ALIGN_NONE +#endif + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* LIB MEM TYPE +* +* Note(s) : (1) 'LIB_MEM_TYPE' declared as 'CPU_INT32U' & all 'LIB_MEM_TYPE's #define'd with large, non-trivial +* values to trap & discard invalid/corrupted library memory objects based on 'LIB_MEM_TYPE'. +********************************************************************************************************* +*/ + +typedef CPU_INT32U LIB_MEM_TYPE; + + +/* +********************************************************************************************************* +* MEMORY POOL BLOCK QUANTITY DATA TYPE +********************************************************************************************************* +*/ + +typedef CPU_SIZE_T MEM_POOL_BLK_QTY; + + +/* +********************************************************************************************************* +* MEMORY POOL TABLE IX TYPE +********************************************************************************************************* +*/ + +typedef MEM_POOL_BLK_QTY MEM_POOL_IX; + + +/* +********************************************************************************************************* +* MEMORY ALLOCATION TRACKING INFO DATA TYPE +********************************************************************************************************* +*/ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +typedef struct mem_alloc_info MEM_ALLOC_INFO; + +struct mem_alloc_info { /* ------------------ MEM ALLOC INFO ------------------ */ + const CPU_CHAR *NamePtr; /* Ptr to name. */ + CPU_SIZE_T Size; /* Total alloc'd size, in bytes. */ + MEM_ALLOC_INFO *NextPtr; /* Ptr to next alloc info in list. */ +}; +#endif + + +/* +********************************************************************************************************* +* MEMORY SEGMENTS DATA TYPES +********************************************************************************************************* +*/ + +typedef struct mem_seg MEM_SEG; /* --------------------- SEG DATA --------------------- */ + +struct mem_seg { + CPU_ADDR AddrBase; /* Seg start addr. */ + CPU_ADDR AddrEnd; /* Seg end addr (last addr). */ + CPU_ADDR AddrNext; /* Next free addr. */ + + MEM_SEG *NextPtr; /* Ptr to next seg. */ + + CPU_SIZE_T PaddingAlign; /* Padding alignment in byte. */ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + const CPU_CHAR *NamePtr; /* Ptr to seg name. */ + MEM_ALLOC_INFO *AllocInfoHeadPtr; /* Ptr to head of alloc info struct list. */ +#endif +}; + +typedef struct mem_seg_info { /* --------------------- SEG INFO --------------------- */ + CPU_SIZE_T UsedSize; /* Used size, independently of alignment. */ + CPU_SIZE_T TotalSize; /* Total seg capacity, in octets. */ + + CPU_ADDR AddrBase; + CPU_ADDR AddrNextAlloc; /* Next aligned address, 0 if none available. */ +} MEM_SEG_INFO; + + +/* +********************************************************************************************************* +* (STATIC) MEMORY POOL DATA TYPES +* +* Note(s) : (1) Free static memory pool blocks are indexed in the 'BlkFreeTbl' table. Newly freed blocks +* are added at the first available position in the table and blocks are retrieved from the +* last occupied position, in a LIFO fashion. +* +* /-------------------------------\ +* |/------------\ | +* BlkFreeTbl || Start v v End +* /--------\ || /--------------------------------------------\ +* |p_free_1|---/| | | | | | | +* |--------| | \--------------------------------------------/ +* |p_free_2|----/ ^ | | +* |--------| | |__Blk___| +* |p_free_3|--------/ (Next block to be retrieved.) Size +* |--------| +* | |<-------- (Next block to be freed.) +* \--------/ +* +********************************************************************************************************* +*/ + + /* --------------------- MEM POOL --------------------- */ +typedef struct mem_pool { + void *PoolAddrStart; /* Ptr to start of mem seg for mem pool blks. */ + void *PoolAddrEnd; /* Ptr to end of mem seg for mem pool blks. */ + MEM_POOL_BLK_QTY BlkNbr; /* Nbr of mem pool blks. */ + CPU_SIZE_T BlkSize; /* Size of mem pool blks (in octets). */ + void **BlkFreeTbl; /* Tbl of free mem pool blks. */ + CPU_SIZE_T BlkFreeTblIx; /* Ix of next free blk free tbl entry. */ +} MEM_POOL; + + +/* +********************************************************************************************************* +* DYNAMIC MEMORY POOL DATA TYPE +* +* Note(s) : (1) Dynamic memory pool blocks are not indexed in a table. Only freed blocks are linked using +* a singly linked list, in a LIFO fashion; newly freed blocks are inserted at the head of the +* list and blocks are also retrieved from the head of the list. +* +* (2) Pointers to the next block are only present when a block is free, using the first location +* in the allocated memory block. The user of dynamic memory pool must not assume his data +* will not be overwritten when a block is freed. +* +* /----------------\ +* /----------\ | /----------\ | /----------\ /----------\ +* BlkFreePtr-->|(NextPtr) |---/ | | \--->|(NextPtr) |-->|(NextPtr) |--> DEF_NULL +* |----------| | Blk in | |----------| |----------| +* | | | use | | | | | +* | | | | | | | | +* \----------/ \----------/ \----------/ \----------/ +* +********************************************************************************************************* +*/ + +typedef struct mem_dyn_pool { /* ---------------- DYN MEM POOL DATA ----------------- */ + MEM_SEG *PoolSegPtr; /* Mem pool from which blks are alloc'd. */ + CPU_SIZE_T BlkSize; /* Size of pool blks, in octets. */ + CPU_SIZE_T BlkAlign; /* Align req'd for blks, in octets. */ + CPU_SIZE_T BlkPaddingAlign; /* Padding alignment in bytes for this mem seg. */ + void *BlkFreePtr; /* Ptr to first free blk. */ + + CPU_SIZE_T BlkQtyMax; /* Max qty of blk in dyn mem pool. 0 = unlimited. */ + CPU_SIZE_T BlkAllocCnt; /* Cnt of alloc blk. */ + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) + const CPU_CHAR *NamePtr; /* Ptr to mem pool name. */ +#endif +} MEM_DYN_POOL; + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY DATA VALUE MACRO'S +* +* Note(s) : (1) (a) Some variables & variable buffers to pass & receive data values MUST start on appropriate +* CPU word-aligned addresses. This is required because most word-aligned processors are more +* efficient & may even REQUIRE that multi-octet words start on CPU word-aligned addresses. +* +* (1) For 16-bit word-aligned processors, this means that +* +* all 16- & 32-bit words MUST start on addresses that are multiples of 2 octets +* +* (2) For 32-bit word-aligned processors, this means that +* +* all 16-bit words MUST start on addresses that are multiples of 2 octets +* all 32-bit words MUST start on addresses that are multiples of 4 octets +* +* (b) However, some data values macro's appropriately access data values from any CPU addresses, +* word-aligned or not. Thus for processors that require data word alignment, data words can +* be accessed to/from any CPU address, word-aligned or not, without generating data-word- +* alignment exceptions/faults. +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* ENDIAN WORD ORDER MACRO'S +* +* Description : Convert data values to & from big-, little, or host-endian CPU word order. +* +* Argument(s) : val Data value to convert (see Notes #1 & #2). +* +* Return(s) : Converted data value (see Notes #1 & #2). +* +* Caller(s) : Application. +* +* Note(s) : (1) Convert data values to the desired data-word order : +* +* MEM_VAL_BIG_TO_LITTLE_xx() Convert big- endian data values +* to little- endian data values +* MEM_VAL_LITTLE_TO_BIG_xx() Convert little- endian data values +* to big- endian data values +* MEM_VAL_xxx_TO_HOST_xx() Convert big-/little-endian data values +* to host- endian data values +* MEM_VAL_HOST_TO_xxx_xx() Convert host- endian data values +* to big-/little-endian data values +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) 'val' data value to convert & any variable to receive the returned conversion MUST +* start on appropriate CPU word-aligned addresses. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1a'. +* +* (3) MEM_VAL_COPY_xxx() macro's are more efficient than generic endian word order macro's & +* are also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4' +* & 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (4) Generic endian word order macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (5) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if ((CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_64) || \ + (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_32)) + +#define MEM_VAL_BIG_TO_LITTLE_16(val) ((CPU_INT16U)(((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_BIG_TO_LITTLE_32(val) ((CPU_INT32U)(((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) << (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) << (3u * DEF_OCTET_NBR_BITS))))) + +#elif (CPU_CFG_DATA_SIZE == CPU_WORD_SIZE_16) + +#define MEM_VAL_BIG_TO_LITTLE_16(val) ((CPU_INT16U)(((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT16U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_BIG_TO_LITTLE_32(val) ((CPU_INT32U)(((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) << (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))) | \ + ((CPU_INT32U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) << (1u * DEF_OCTET_NBR_BITS))))) + +#else + +#define MEM_VAL_BIG_TO_LITTLE_16(val) (val) +#define MEM_VAL_BIG_TO_LITTLE_32(val) (val) + +#endif + + +#define MEM_VAL_LITTLE_TO_BIG_16(val) MEM_VAL_BIG_TO_LITTLE_16(val) +#define MEM_VAL_LITTLE_TO_BIG_32(val) MEM_VAL_BIG_TO_LITTLE_32(val) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_BIG_TO_HOST_16(val) (val) +#define MEM_VAL_BIG_TO_HOST_32(val) (val) +#define MEM_VAL_LITTLE_TO_HOST_16(val) MEM_VAL_LITTLE_TO_BIG_16(val) +#define MEM_VAL_LITTLE_TO_HOST_32(val) MEM_VAL_LITTLE_TO_BIG_32(val) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_BIG_TO_HOST_16(val) MEM_VAL_BIG_TO_LITTLE_16(val) +#define MEM_VAL_BIG_TO_HOST_32(val) MEM_VAL_BIG_TO_LITTLE_32(val) +#define MEM_VAL_LITTLE_TO_HOST_16(val) (val) +#define MEM_VAL_LITTLE_TO_HOST_32(val) (val) + +#else /* See Note #5. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +#define MEM_VAL_HOST_TO_BIG_16(val) MEM_VAL_BIG_TO_HOST_16(val) +#define MEM_VAL_HOST_TO_BIG_32(val) MEM_VAL_BIG_TO_HOST_32(val) +#define MEM_VAL_HOST_TO_LITTLE_16(val) MEM_VAL_LITTLE_TO_HOST_16(val) +#define MEM_VAL_HOST_TO_LITTLE_32(val) MEM_VAL_LITTLE_TO_HOST_32(val) + + +/* +********************************************************************************************************* +* MEM_VAL_GET_xxx() +* +* Description : Decode data values from any CPU memory address. +* +* Argument(s) : addr Lowest CPU memory address of data value to decode (see Notes #2 & #3a). +* +* Return(s) : Decoded data value from CPU memory address (see Notes #1 & #3b). +* +* Caller(s) : Application. +* +* Note(s) : (1) Decode data values based on the values' data-word order in CPU memory : +* +* MEM_VAL_GET_xxx_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_GET_xxx_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_GET_xxx() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) CPU memory addresses/pointers NOT checked for NULL. +* +* (3) (a) MEM_VAL_GET_xxx() macro's decode data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be decoded from any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (b) However, any variable to receive the returned data value MUST start on an appropriate CPU +* word-aligned address. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1'. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_GET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4'. +* +* (5) MEM_VAL_GET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#define MEM_VAL_GET_INT08U_BIG(addr) ((CPU_INT08U) ((CPU_INT08U)(((CPU_INT08U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS)))) + +#define MEM_VAL_GET_INT16U_BIG(addr) ((CPU_INT16U)(((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 0))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 1))) << (0u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT24U_BIG(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (2u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (0u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT32U_BIG(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (3u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (2u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 3))) << (0u * DEF_OCTET_NBR_BITS))))) + + + +#define MEM_VAL_GET_INT08U_LITTLE(addr) ((CPU_INT08U) ((CPU_INT08U)(((CPU_INT08U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS)))) + +#define MEM_VAL_GET_INT16U_LITTLE(addr) ((CPU_INT16U)(((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT16U)(((CPU_INT16U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT24U_LITTLE(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (2u * DEF_OCTET_NBR_BITS))))) + +#define MEM_VAL_GET_INT32U_LITTLE(addr) ((CPU_INT32U)(((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 0))) << (0u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 1))) << (1u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 2))) << (2u * DEF_OCTET_NBR_BITS))) + \ + ((CPU_INT32U)(((CPU_INT32U)(*(((CPU_INT08U *)(addr)) + 3))) << (3u * DEF_OCTET_NBR_BITS))))) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_GET_INT08U(addr) MEM_VAL_GET_INT08U_BIG(addr) +#define MEM_VAL_GET_INT16U(addr) MEM_VAL_GET_INT16U_BIG(addr) +#define MEM_VAL_GET_INT24U(addr) MEM_VAL_GET_INT24U_BIG(addr) +#define MEM_VAL_GET_INT32U(addr) MEM_VAL_GET_INT32U_BIG(addr) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_GET_INT08U(addr) MEM_VAL_GET_INT08U_LITTLE(addr) +#define MEM_VAL_GET_INT16U(addr) MEM_VAL_GET_INT16U_LITTLE(addr) +#define MEM_VAL_GET_INT24U(addr) MEM_VAL_GET_INT24U_LITTLE(addr) +#define MEM_VAL_GET_INT32U(addr) MEM_VAL_GET_INT32U_LITTLE(addr) + +#else /* See Note #6. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_SET_xxx() +* +* Description : Encode data values to any CPU memory address. +* +* Argument(s) : addr Lowest CPU memory address to encode data value (see Notes #2 & #3a). +* +* val Data value to encode (see Notes #1 & #3b). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Encode data values into CPU memory based on the values' data-word order : +* +* MEM_VAL_SET_xxx_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_SET_xxx_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_SET_xxx() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) CPU memory addresses/pointers NOT checked for NULL. +* +* (3) (a) MEM_VAL_SET_xxx() macro's encode data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be encoded to any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (b) However, 'val' data value to encode MUST start on an appropriate CPU word-aligned address. +* +* See also 'MEMORY DATA VALUE MACRO'S Note #1'. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_SET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (5) MEM_VAL_SET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#define MEM_VAL_SET_INT08U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT08U)(val)) & (CPU_INT08U) 0xFFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT16U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT24U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0xFF0000u) >> (2u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0x00FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0x0000FFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT32U_BIG(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (2u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 3)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + + + +#define MEM_VAL_SET_INT08U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT08U)(val)) & (CPU_INT08U) 0xFFu) >> (0u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT16U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0x00FFu) >> (0u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT16U)(val)) & (CPU_INT16U) 0xFF00u) >> (1u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT24U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0x0000FFu) >> (0u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0x00FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U) 0xFF0000u) >> (2u * DEF_OCTET_NBR_BITS))); } while (0) + +#define MEM_VAL_SET_INT32U_LITTLE(addr, val) do { (*(((CPU_INT08U *)(addr)) + 0)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x000000FFu) >> (0u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 1)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x0000FF00u) >> (1u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 2)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0x00FF0000u) >> (2u * DEF_OCTET_NBR_BITS))); \ + (*(((CPU_INT08U *)(addr)) + 3)) = ((CPU_INT08U)((((CPU_INT32U)(val)) & (CPU_INT32U)0xFF000000u) >> (3u * DEF_OCTET_NBR_BITS))); } while (0) + + + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + +#define MEM_VAL_SET_INT08U(addr, val) MEM_VAL_SET_INT08U_BIG((addr), (val)) +#define MEM_VAL_SET_INT16U(addr, val) MEM_VAL_SET_INT16U_BIG((addr), (val)) +#define MEM_VAL_SET_INT24U(addr, val) MEM_VAL_SET_INT24U_BIG((addr), (val)) +#define MEM_VAL_SET_INT32U(addr, val) MEM_VAL_SET_INT32U_BIG((addr), (val)) + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + +#define MEM_VAL_SET_INT08U(addr, val) MEM_VAL_SET_INT08U_LITTLE((addr), (val)) +#define MEM_VAL_SET_INT16U(addr, val) MEM_VAL_SET_INT16U_LITTLE((addr), (val)) +#define MEM_VAL_SET_INT24U(addr, val) MEM_VAL_SET_INT24U_LITTLE((addr), (val)) +#define MEM_VAL_SET_INT32U(addr, val) MEM_VAL_SET_INT32U_LITTLE((addr), (val)) + +#else /* See Note #6. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_GET_xxx() +* +* Description : Copy & decode data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/decode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/decode +* (see Notes #2 & #3). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/decode data values based on the values' data-word order : +* +* MEM_VAL_COPY_GET_xxx_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_xxx_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_xxx() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_GET_xxx() macro's copy/decode data values without regard to CPU word-aligned +* addresses. Thus for processors that require data word alignment, data words can be copied/ +* decoded to/from any CPU address, word-aligned or not, without generating data-word-alignment +* exceptions/faults. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_GET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_GET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_xxx() & +* MEM_VAL_COPY_SET_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_GET_xxx() macro's are NOT atomic operations & MUST NOT be used on any non- +* static (i.e. volatile) variables, registers, hardware, etc.; without the caller of the +* macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (7) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + + +#define MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_GET_INT24U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT24U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 3)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + + +#define MEM_VAL_COPY_GET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT24U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT24U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_BIG((addr_dest), (addr_src)) + + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + + +#define MEM_VAL_COPY_GET_INT08U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT24U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_BIG(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 3)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + + + +#define MEM_VAL_COPY_GET_INT08U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_GET_INT16U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_GET_INT24U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); } while (0) + +#define MEM_VAL_COPY_GET_INT32U_LITTLE(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + +#define MEM_VAL_COPY_GET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT24U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT24U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_GET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_LITTLE((addr_dest), (addr_src)) + + +#else /* See Note #7. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_GET_INTU_xxx() +* +* Description : Copy & decode data values from any CPU memory address to any CPU memory address for +* any sized data values. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/decode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/decode +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy/decode. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/decode data values based on the values' data-word order : +* +* MEM_VAL_COPY_GET_INTU_BIG() Decode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_INTU_LITTLE() Decode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_GET_INTU() Decode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_GET_INTU_xxx() macro's copy/decode data values without regard to CPU word- +* aligned addresses. Thus for processors that require data word alignment, data words +* can be copied/decoded to/from any CPU address, word-aligned or not, without generating +* data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_GET_xxx() macro's are more efficient than MEM_VAL_COPY_GET_INTU_xxx() +* macro's & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_INTU_xxx() & +* MEM_VAL_COPY_SET_INTU_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_SET_INTU_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_GET_INTU_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +* +* (7) MISRA-C 2004 Rule 5.2 states that "identifiers in an inner scope shall not use the same +* name as an indentifier in an outer scope, and therefore hide that identifier". +* +* Therefore, to avoid possible redeclaration of commonly-used loop counter identifier names, +* 'i' & 'j', MEM_VAL_COPY_GET_INTU_xxx() loop counter identifier names are prefixed with a +* single underscore. +* +* (8) The 'CPU_CFG_ENDIAN_TYPE' pre-processor 'else'-conditional code SHOULD never be compiled/ +* linked since each 'cpu.h' SHOULD ensure that the CPU data-word-memory order configuration +* constant (CPU_CFG_ENDIAN_TYPE) is configured with an appropriate data-word-memory order +* value (see 'cpu.h CPU WORD CONFIGURATION Note #2'). The 'else'-conditional code is +* included as an extra precaution in case 'cpu.h' is incorrectly configured. +********************************************************************************************************* +*/ + +#if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + + +#define MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _i)); \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + CPU_SIZE_T _j; \ + \ + \ + _j = (val_size) - 1; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _j)); \ + _j--; \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_BIG((addr_dest), (addr_src), (val_size)) + + + + +#elif (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_LITTLE) + + +#define MEM_VAL_COPY_GET_INTU_BIG(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + CPU_SIZE_T _j; \ + \ + \ + _j = (val_size) - 1; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _j)); \ + _j--; \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU_LITTLE(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) + _i)) = (*(((CPU_INT08U *)(addr_src)) + _i)); \ + } \ + } while (0) + + +#define MEM_VAL_COPY_GET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_LITTLE((addr_dest), (addr_src), (val_size)) + + + + +#else /* See Note #8. */ + +#error "CPU_CFG_ENDIAN_TYPE illegally #defined in 'cpu.h' " +#error " [See 'cpu.h CONFIGURATION ERRORS']" + +#endif + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_SET_xxx() +* +* Description : Copy & encode data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/encode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/encode +* (see Notes #2 & #3). +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/encode data values based on the values' data-word order : +* +* MEM_VAL_COPY_SET_xxx_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_xxx_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_xxx() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_SET_xxx() macro's copy/encode data values without regard to CPU word-aligned +* addresses. Thus for processors that require data word alignment, data words can be copied/ +* encoded to/from any CPU address, word-aligned or not, without generating data-word-alignment +* exceptions/faults. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_SET_xxx() macro's & are +* also independent of CPU data-word-alignment & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_SET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_xxx() & +* MEM_VAL_COPY_SET_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_GET_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_SET_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller +* of the macro's providing some form of additional protection (e.g. mutual exclusion). +********************************************************************************************************* +*/ + + /* See Note #5. */ +#define MEM_VAL_COPY_SET_INT08U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT16U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT24U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT24U_BIG((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT32U_BIG(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_BIG((addr_dest), (addr_src)) + +#define MEM_VAL_COPY_SET_INT08U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT16U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT24U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT24U_LITTLE((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT32U_LITTLE(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U_LITTLE((addr_dest), (addr_src)) + + +#define MEM_VAL_COPY_SET_INT08U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT08U((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT16U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT16U((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT24U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT24U((addr_dest), (addr_src)) +#define MEM_VAL_COPY_SET_INT32U(addr_dest, addr_src) MEM_VAL_COPY_GET_INT32U((addr_dest), (addr_src)) + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_SET_INTU_xxx() +* +* Description : Copy & encode data values from any CPU memory address to any CPU memory address for +* any sized data values. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy/encode source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy/encode +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy/encode. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) Copy/encode data values based on the values' data-word order : +* +* MEM_VAL_COPY_SET_INTU_BIG() Encode big- endian data values -- data words' most +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_INTU_LITTLE() Encode little-endian data values -- data words' least +* significant octet @ lowest memory address +* MEM_VAL_COPY_SET_INTU() Encode data values using CPU's native or configured +* data-word order +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_SET_INTU_xxx() macro's copy/encode data values without regard to CPU word- +* aligned addresses. Thus for processors that require data word alignment, data words +* can be copied/encoded to/from any CPU address, word-aligned or not, without generating +* data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_SET_xxx() macro's are more efficient than MEM_VAL_COPY_SET_INTU_xxx() +* macro's & SHOULD be used whenever possible. +* +* See also 'MEM_VAL_COPY_SET_xxx() Note #4'. +* +* (5) Since octet-order copy/conversion are inverse operations, MEM_VAL_COPY_GET_INTU_xxx() & +* MEM_VAL_COPY_SET_INTU_xxx() macros are inverse, but identical, operations & are provided +* in both forms for semantics & consistency. +* +* See also 'MEM_VAL_COPY_GET_INTU_xxx() Note #5'. +* +* (6) MEM_VAL_COPY_SET_INTU_xxx() macro's are NOT atomic operations & MUST NOT be used on any +* non-static (i.e. volatile) variables, registers, hardware, etc.; without the caller of +* the macro's providing some form of additional protection (e.g. mutual exclusion). +********************************************************************************************************* +*/ + + /* See Note #5. */ +#define MEM_VAL_COPY_SET_INTU_BIG(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_BIG((addr_dest), (addr_src), (val_size)) +#define MEM_VAL_COPY_SET_INTU_LITTLE(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU_LITTLE((addr_dest), (addr_src), (val_size)) +#define MEM_VAL_COPY_SET_INTU(addr_dest, addr_src, val_size) MEM_VAL_COPY_GET_INTU((addr_dest), (addr_src), (val_size)) + + +/* +********************************************************************************************************* +* MEM_VAL_COPY_xxx() +* +* Description : Copy data values from any CPU memory address to any CPU memory address. +* +* Argument(s) : addr_dest Lowest CPU memory address to copy source address's data value +* (see Notes #2 & #3). +* +* addr_src Lowest CPU memory address of data value to copy +* (see Notes #2 & #3). +* +* val_size Number of data value octets to copy. +* +* Return(s) : none. +* +* Caller(s) : Application. +* +* Note(s) : (1) MEM_VAL_COPY_xxx() macro's copy data values based on CPU's native data-word order. +* +* See also 'cpu.h CPU WORD CONFIGURATION Note #2'. +* +* (2) (a) CPU memory addresses/pointers NOT checked for NULL. +* +* (b) CPU memory addresses/buffers NOT checked for overlapping. +* +* (1) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that +* "copying ... between objects that overlap ... is undefined". +* +* (3) MEM_VAL_COPY_xxx() macro's copy data values without regard to CPU word-aligned addresses. +* Thus for processors that require data word alignment, data words can be copied to/from any +* CPU address, word-aligned or not, without generating data-word-alignment exceptions/faults. +* +* (4) MEM_VAL_COPY_xxx() macro's are more efficient than MEM_VAL_COPY() macro & SHOULD be +* used whenever possible. +* +* (5) MEM_VAL_COPY_xxx() macro's are NOT atomic operations & MUST NOT be used on any non-static +* (i.e. volatile) variables, registers, hardware, etc.; without the caller of the macro's +* providing some form of additional protection (e.g. mutual exclusion). +* +* (6) MISRA-C 2004 Rule 5.2 states that "identifiers in an inner scope shall not use the same +* name as an indentifier in an outer scope, and therefore hide that identifier". +* +* Therefore, to avoid possible redeclaration of commonly-used loop counter identifier name, +* 'i', MEM_VAL_COPY() loop counter identifier name is prefixed with a single underscore. +********************************************************************************************************* +*/ + +#define MEM_VAL_COPY_08(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); } while (0) + +#define MEM_VAL_COPY_16(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); } while (0) + +#define MEM_VAL_COPY_24(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); } while (0) + +#define MEM_VAL_COPY_32(addr_dest, addr_src) do { (*(((CPU_INT08U *)(addr_dest)) + 0)) = (*(((CPU_INT08U *)(addr_src)) + 0)); \ + (*(((CPU_INT08U *)(addr_dest)) + 1)) = (*(((CPU_INT08U *)(addr_src)) + 1)); \ + (*(((CPU_INT08U *)(addr_dest)) + 2)) = (*(((CPU_INT08U *)(addr_src)) + 2)); \ + (*(((CPU_INT08U *)(addr_dest)) + 3)) = (*(((CPU_INT08U *)(addr_src)) + 3)); } while (0) + + +#define MEM_VAL_COPY(addr_dest, addr_src, val_size) do { \ + CPU_SIZE_T _i; \ + \ + for (_i = 0; _i < (val_size); _i++) { \ + (*(((CPU_INT08U *)(addr_dest)) +_i)) = (*(((CPU_INT08U *)(addr_src)) +_i)); \ + } \ + } while (0) + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void Mem_Init ( void); + + /* ------------------ MEM API FNCTS ------------------ */ +void Mem_Clr ( void *pmem, + CPU_SIZE_T size); + +void Mem_Set ( void *pmem, + CPU_INT08U data_val, + CPU_SIZE_T size); + +void Mem_Copy ( void *pdest, + const void *psrc, + CPU_SIZE_T size); + +void Mem_Move ( void *pdest, + const void *psrc, + CPU_SIZE_T size); + +CPU_BOOLEAN Mem_Cmp (const void *p1_mem, + const void *p2_mem, + CPU_SIZE_T size); + + + /* ----------- MEM HEAP FNCTS (DEPRECATED) ------------ */ +#if (LIB_MEM_CFG_HEAP_SIZE > 0u) +void *Mem_HeapAlloc ( CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_HeapGetSizeRem ( CPU_SIZE_T align, + LIB_ERR *p_err); +#endif + + /* ------------------ MEM SEG FNCTS ------------------- */ +void Mem_SegCreate (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_ADDR seg_base_addr, + CPU_SIZE_T size, + CPU_SIZE_T padding_align, + LIB_ERR *p_err); + +void Mem_SegClr ( MEM_SEG *p_seg, + LIB_ERR *p_err); + +void *Mem_SegAlloc (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + LIB_ERR *p_err); + +void *Mem_SegAllocExt (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +void *Mem_SegAllocHW (const CPU_CHAR *p_name, + MEM_SEG *p_seg, + CPU_SIZE_T size, + CPU_SIZE_T align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_SegRemSizeGet ( MEM_SEG *p_seg, + CPU_SIZE_T align, + MEM_SEG_INFO *p_seg_info, + LIB_ERR *p_err); + +#if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) +void Mem_OutputUsage ( void (*out_fnct) (CPU_CHAR *), + LIB_ERR *p_err); +#endif + + /* -------- STATIC MEM POOL FNCTS (DEPRECATED) -------- */ +void Mem_PoolCreate ( MEM_POOL *p_pool, + void *p_mem_base, + CPU_SIZE_T mem_size, + MEM_POOL_BLK_QTY blk_nbr, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T *p_bytes_reqd, + LIB_ERR *p_err); + +void Mem_PoolClr ( MEM_POOL *p_pool, + LIB_ERR *p_err); + +void *Mem_PoolBlkGet ( MEM_POOL *p_pool, + CPU_SIZE_T size, + LIB_ERR *p_err); + +void Mem_PoolBlkFree ( MEM_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err); + +MEM_POOL_BLK_QTY Mem_PoolBlkGetNbrAvail ( MEM_POOL *p_pool, + LIB_ERR *p_err); + + /* -------------- DYNAMIC MEM POOL FNCTS -------------- */ +void Mem_DynPoolCreate (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +void Mem_DynPoolCreateHW (const CPU_CHAR *p_name, + MEM_DYN_POOL *p_pool, + MEM_SEG *p_seg, + CPU_SIZE_T blk_size, + CPU_SIZE_T blk_align, + CPU_SIZE_T blk_qty_init, + CPU_SIZE_T blk_qty_max, + LIB_ERR *p_err); + +void *Mem_DynPoolBlkGet ( MEM_DYN_POOL *p_pool, + LIB_ERR *p_err); + +void Mem_DynPoolBlkFree ( MEM_DYN_POOL *p_pool, + void *p_blk, + LIB_ERR *p_err); + +CPU_SIZE_T Mem_DynPoolBlkNbrAvailGet( MEM_DYN_POOL *p_pool, + LIB_ERR *p_err); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef LIB_MEM_CFG_ARG_CHK_EXT_EN +#error "LIB_MEM_CFG_ARG_CHK_EXT_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_ARG_CHK_EXT_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_ARG_CHK_EXT_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_ARG_CHK_EXT_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " +#endif + + + +#ifndef LIB_MEM_CFG_OPTIMIZE_ASM_EN +#error "LIB_MEM_CFG_OPTIMIZE_ASM_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_OPTIMIZE_ASM_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " +#endif + + +#ifndef LIB_MEM_CFG_HEAP_SIZE +#error "LIB_MEM_CFG_HEAP_SIZE not #define'd in 'lib_cfg.h'" +#error " [MUST be >= 0] " +#endif + + +#ifdef LIB_MEM_CFG_HEAP_BASE_ADDR +#if (LIB_MEM_CFG_HEAP_BASE_ADDR == 0x0) +#error "LIB_MEM_CFG_HEAP_BASE_ADDR illegally #define'd in 'lib_cfg.h'" +#error " [MUST be > 0x0] " +#endif +#endif + + +#if ((LIB_MEM_CFG_DBG_INFO_EN != DEF_DISABLED) && \ + (LIB_MEM_CFG_DBG_INFO_EN != DEF_ENABLED )) +#error "LIB_MEM_CFG_DBG_INFO_EN illegally defined in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_MEM_CFG_HEAP_SIZE == 0u) && \ + (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)) +#error "LIB_MEM_CFG_HEAP_SIZE illegally defined in 'lib_cfg.h' " +#error " [MUST be > 0 when LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED]" +#endif + + +/* +********************************************************************************************************* +* LIBRARY CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + /* See 'lib_mem.h Note #2a'. */ +#if (CPU_CORE_VERSION < 127u) +#error "CPU_CORE_VERSION [SHOULD be >= V1.27]" +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_mem.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib mem module include. */ diff --git a/rtos/uC-LIB/lib_str.c b/rtos/uC-LIB/lib_str.c new file mode 100644 index 00000000..1208dbfa --- /dev/null +++ b/rtos/uC-LIB/lib_str.c @@ -0,0 +1,4031 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII STRING MANAGEMENT +* +* Filename : lib_str.c +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +* +********************************************************************************************************* +* Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given +* us permission to reprint portions of their documentation. Portions of this text are +* reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition, +* Standard for Information Technology -- Portable Operating System Interface (POSIX), +* The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute +* of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any +* discrepancy between these versions and the original IEEE and The Open Group Standard, +* the original IEEE and The Open Group Standard is the referee document. The original +* Standard can be obtained online at http://www.opengroup.org/unix/online.html. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#define LIB_STR_MODULE +#include + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL CONSTANTS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL TABLES +********************************************************************************************************* +*/ + +static const CPU_INT32U Str_MultOvfThTbl_Int32U[] = { + (CPU_INT32U) DEF_INT_32U_MAX_VAL, /* Invalid base 0. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 1u), /* Invalid base 1. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 2u), /* 32-bit mult ovf th for base 2. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 3u), /* 32-bit mult ovf th for base 3. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 4u), /* 32-bit mult ovf th for base 4. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 5u), /* 32-bit mult ovf th for base 5. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 6u), /* 32-bit mult ovf th for base 6. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 7u), /* 32-bit mult ovf th for base 7. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 8u), /* 32-bit mult ovf th for base 8. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 9u), /* 32-bit mult ovf th for base 9. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 10u), /* 32-bit mult ovf th for base 10. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 11u), /* 32-bit mult ovf th for base 11. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 12u), /* 32-bit mult ovf th for base 12. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 13u), /* 32-bit mult ovf th for base 13. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 14u), /* 32-bit mult ovf th for base 14. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 15u), /* 32-bit mult ovf th for base 15. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 16u), /* 32-bit mult ovf th for base 16. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 17u), /* 32-bit mult ovf th for base 17. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 18u), /* 32-bit mult ovf th for base 18. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 19u), /* 32-bit mult ovf th for base 19. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 20u), /* 32-bit mult ovf th for base 20. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 21u), /* 32-bit mult ovf th for base 21. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 22u), /* 32-bit mult ovf th for base 22. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 23u), /* 32-bit mult ovf th for base 23. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 24u), /* 32-bit mult ovf th for base 24. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 25u), /* 32-bit mult ovf th for base 25. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 26u), /* 32-bit mult ovf th for base 26. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 27u), /* 32-bit mult ovf th for base 27. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 28u), /* 32-bit mult ovf th for base 28. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 29u), /* 32-bit mult ovf th for base 29. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 30u), /* 32-bit mult ovf th for base 30. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 31u), /* 32-bit mult ovf th for base 31. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 32u), /* 32-bit mult ovf th for base 32. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 33u), /* 32-bit mult ovf th for base 33. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 34u), /* 32-bit mult ovf th for base 34. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 35u), /* 32-bit mult ovf th for base 35. */ + (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 36u) /* 32-bit mult ovf th for base 36. */ +}; + + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static CPU_CHAR *Str_FmtNbr_Int32 ( CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_neg, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +static CPU_INT32U Str_ParseNbr_Int32(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_signed, + CPU_BOOLEAN *pnbr_neg); + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* Str_Len() +* +* Description : Calculate length of a string. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* Return(s) : Length of string; number of characters in string before terminating NULL character +* (see Note #2b1). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that : +* +* (1) "The strlen() function shall compute the number of bytes in the string to +* which 's' ('pstr') points," ... +* (2) "not including the terminating null byte." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that : +* +* (1) "The strlen() function shall return the length of 's' ('pstr');" ... +* (2) "no return value shall be reserved to indicate an error." +* +* (3) String length calculation terminates when : +* +* (a) String pointer points to NULL. +* (1) String buffer overlaps with NULL address. +* (2) String length calculated for string up to but NOT beyond or including +* the NULL address. +* +* (b) Terminating NULL character found. +* (1) String length calculated for string up to but NOT including +* the NULL character (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_SIZE_T Str_Len (const CPU_CHAR *pstr) +{ + CPU_SIZE_T len; + + + len = Str_Len_N(pstr, + DEF_INT_CPU_U_MAX_VAL); + + return (len); +} + + +/* +********************************************************************************************************* +* Str_Len_N() +* +* Description : Calculate length of a string, up to a maximum number of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Note #3c). +* +* Return(s) : Length of string; number of characters in string before terminating NULL character, +* if terminating NULL character found (see Note #2b1). +* +* Requested maximum number of characters to search, +* if terminating NULL character NOT found (see Note #3c). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that : +* +* (1) "The strlen() function shall compute the number of bytes in the string to +* which 's' ('pstr') points," ... +* (2) "not including the terminating null byte." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that : +* +* (1) "The strlen() function shall return the length of 's' ('pstr');" ... +* (2) "no return value shall be reserved to indicate an error." +* +* (3) String length calculation terminates when : +* +* (a) String pointer points to NULL. +* (1) String buffer overlaps with NULL address. +* (2) String length calculated for string up to but NOT beyond or including +* the NULL address. +* +* (b) Terminating NULL character found. +* (1) String length calculated for string up to but NOT including +* the NULL character (see Note #2a2). +* +* (c) 'len_max' number of characters searched. +* (1) 'len_max' number of characters does NOT include the terminating NULL character. +********************************************************************************************************* +*/ + +CPU_SIZE_T Str_Len_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *pstr_len; + CPU_SIZE_T len; + + + pstr_len = pstr; + len = 0u; + while (( pstr_len != (const CPU_CHAR *) 0 ) && /* Calc str len until NULL ptr (see Note #3a) ... */ + (*pstr_len != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3b) ... */ + ( len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3c). */ + pstr_len++; + len++; + } + + return (len); /* Rtn str len (see Note #3b1). */ +} + + +/* +********************************************************************************************************* +* Str_Copy() +* +* Description : Copy source string to destination string buffer. +* +* Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a). +* +* pstr_src Pointer to source string to copy into destination string buffer (see Note #1b). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire source +* string size including the terminating NULL character. +* +* (b) Source buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that : +* +* (1) "The strcpy() function shall copy the string pointed to by 's2' ('pstr_src') +* ... into the array pointed to by 's1' ('pstr_dest')" ... +* (2) "(including the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : RETURN VALUE' states that : +* +* (1) "The strcpy() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value is reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (3) String copy terminates when : +* +* (a) Destination/Source string pointer(s) are passed NULL pointers. +* (1) No string copy performed; NULL pointer returned. +* +* (b) Destination/Source string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Source string's terminating NULL character found. +* (1) Entire source string copied into destination string buffer (see Note #2a). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Copy ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Copy_N(pstr_dest, + pstr_src, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Copy_N() +* +* Description : Copy source string to destination string buffer, up to a maximum number of characters. +* +* Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a). +* +* pstr_src Pointer to source string to copy into destination string buffer (see Note #1b). +* +* len_max Maximum number of characters to copy (see Notes #2a2 & #3d). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire source +* string size including the terminating NULL character. +* +* (b) Source string buffer NOT modified. +* +* (2) (a) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that : +* +* (A) "The strncpy() function shall copy ... the array pointed to by 's2' +* ('pstr_src') to the array pointed to by 's1' ('pstr_dest')"; ... +* (B) but "not more than 'n' ('len_max') bytes" ... +* (C) & "(bytes that follow a null byte are not copied)". +* +* (2) (A) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' adds that +* "if the array pointed to by 's2' ('pstr_src') is a string that is shorter +* than 'n' ('len_max') bytes, null bytes shall be appended to the copy in +* the array pointed to by 's1' ('pstr_dest'), until 'n' ('len_max') bytes +* in all are written." +* +* (1) #### Since Str_Copy() limits the maximum number of characters to copy +* via Str_Copy_N() by the CPU's maximum number of addressable characters, +* this requirement is intentionally NOT implemented to avoid appending +* a potentially large number of unnecessary terminating NULL characters. +* +* (B) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : APPLICATION USAGE' also +* states that "if there is no null byte in the first 'n' ('len_max') bytes of +* the array pointed to by 's2' ('pstr_src'), the result is not null-terminated". +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : RETURN VALUE' states that : +* +* (1) "The strncpy() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value is reserved to indicate an error." +* (A) #### This requirement is intentionally ignored in order to return NULL +* for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined". +* +* (3) String copy terminates when : +* +* (a) Destination/Source string pointer(s) are passed NULL pointers. +* (1) No string copy performed; NULL pointer returned. +* +* (b) Destination/Source string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Source string's terminating NULL character found. +* (1) Entire source string copied into destination string buffer (see Note #2a1A). +* +* (d) 'len_max' number of characters copied. +* (1) 'len_max' number of characters MAY include the terminating NULL character +* (see Note #2a1C). +* (2) Null copies allowed (i.e. zero-length copies). +* (A) No string copy performed; destination string returned (see Note #2b1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Copy_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_copy_dest; + const CPU_CHAR *pstr_copy_src; + CPU_SIZE_T len_copy; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */ + if (pstr_dest == (CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_src == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + + pstr_copy_dest = pstr_dest; + pstr_copy_src = pstr_src; + len_copy = 0u; + + while (( pstr_copy_dest != ( CPU_CHAR *) 0 ) && /* Copy str until NULL ptr(s) [see Note #3b] ... */ + ( pstr_copy_src != (const CPU_CHAR *) 0 ) && + (*pstr_copy_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */ + ( len_copy < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars copied (see Note #3d). */ + *pstr_copy_dest = *pstr_copy_src; + pstr_copy_dest++; + pstr_copy_src++; + len_copy++; + } + + /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */ + if ((pstr_copy_dest == ( CPU_CHAR *)0) || + (pstr_copy_src == (const CPU_CHAR *)0)) { + return ((CPU_CHAR *)0); + } + + if (len_copy < len_max) { /* If copy str len < max buf len (see Note #2a2A), ... */ + *pstr_copy_dest = (CPU_CHAR)'\0'; /* ... copy NULL char (see Note #3c1). */ + } + + + return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */ +} + + +/* +********************************************************************************************************* +* Str_Cat() +* +* Description : Append concatenation string to destination string. +* +* Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a). +* +* pstr_cat Pointer to concatenation string to append to destination string (see Note #1b). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire +* concatenated string size including the terminating NULL character. +* +* (b) Concatenation string buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that : +* +* (1) "The strcat() function shall append a copy of the string pointed to by 's2' +* ('pstr_cat') ... to the end of the string pointed to by 's1' ('pstr_dest')." +* +* (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the +* end of 's1' ('pstr_dest')." +* (B) A "terminating null byte" is appended at the end of the concatenated +* destination strings. +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : RETURN VALUE' states that : +* +* (1) "The strcat() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value shall be reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined." +* +* (3) String concatenation terminates when : +* +* (a) Destination/Concatenation string pointer(s) are passed NULL pointers. +* (1) No string concatenation performed; NULL pointer returned. +* +* (b) Destination/Concatenation string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Concatenation string's terminating NULL character found. +* (1) Entire concatenation string appended to destination string (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Cat ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Cat_N(pstr_dest, + pstr_cat, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Cat_N() +* +* Description : Append concatenation string to destination string, up to a maximum number of characters. +* +* Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a). +* +* pstr_cat Pointer to concatenation string to append to destination string (see Note #1b). +* +* len_max Maximum number of characters to concatenate (see Notes #2a1B & #3d). +* +* Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1]. +* +* Pointer to NULL, otherwise (see Note #2b2A). +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (1) Destination buffer size MUST be large enough to accommodate the entire +* concatenated string size including the terminating NULL character. +* +* (b) Concatenation string buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that : +* +* (1) (A) "The strncat() function shall append ... the array pointed to by 's2' +* ('pstr_cat') to the end of the string pointed to by 's1' ('pstr_dest')" ... +* (B) but "not more than 'n' ('len_max') bytes". +* +* (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the +* end of 's1' ('pstr_dest')." +* (B) "(a null byte and bytes that follow it are not appended)." +* (C) "A terminating null byte is always appended to the result." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : RETURN VALUE' states that : +* +* (1) "The strncat() function shall return 's1' ('pstr_dest');" ... +* (2) "no return value shall be reserved to indicate an error." +* (A) #### This requirement is intentionally NOT implemented in order to return +* NULL for any error(s). +* +* (c) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that "if +* copying takes place between objects that overlap, the behavior is undefined." +* +* (3) String concatenation terminates when : +* +* (a) Destination/Concatenation string pointer(s) are passed NULL pointers. +* (1) No string concatenation performed; NULL pointer returned. +* +* (b) Destination/Concatenation string pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Concatenation string's terminating NULL character found. +* (1) Entire concatenation string appended to destination string (see Note #2a1A). +* +* (d) 'len_max' number of characters concatenated. +* +* (1) 'len_max' number of characters does NOT include the terminating NULL character +* (see Note #2a2). +* +* (2) Null concatenations allowed (i.e. zero-length concatenations). +* (A) No string concatenation performed; destination string returned +* (see Note #2b1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Cat_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_cat_dest; + const CPU_CHAR *pstr_cat_src; + CPU_SIZE_T len_cat; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */ + if (pstr_dest == (CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_cat == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn dest str if cat len = 0 (see Note #3d2A). */ + return ((CPU_CHAR *)pstr_dest); + } + + + pstr_cat_dest = pstr_dest; + while (( pstr_cat_dest != (CPU_CHAR *) 0 ) && /* Adv to end of cur dest str until NULL ptr ... */ + (*pstr_cat_dest != (CPU_CHAR )'\0')) { /* ... or NULL char found.. */ + pstr_cat_dest++; + } + + if (pstr_cat_dest == (CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + pstr_cat_src = pstr_cat; + len_cat = 0u; + + while (( pstr_cat_dest != ( CPU_CHAR *) 0 ) && /* Cat str until NULL ptr(s) [see Note #3b] ... */ + ( pstr_cat_src != (const CPU_CHAR *) 0 ) && + (*pstr_cat_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */ + ( len_cat < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cat'd (see Note #3d). */ + *pstr_cat_dest = *pstr_cat_src; + pstr_cat_dest++; + pstr_cat_src++; + len_cat++; + } + + /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */ + if ((pstr_cat_dest == ( CPU_CHAR *)0) || + (pstr_cat_src == (const CPU_CHAR *)0)) { + return ((CPU_CHAR *)0); + } + + *pstr_cat_dest = (CPU_CHAR)'\0'; /* Append NULL char (see Note #2a2C). */ + + + return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */ +} + + +/* +********************************************************************************************************* +* Str_Cmp() +* +* Description : Determine if two strings are identical. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' states that "the +* strcmp() function shall compare the string pointed to by 's1' ('p1_str') to the +* string pointed to by 's2' ('p2_str)". +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : RETURN VALUE' states that +* "upon successful completion, strcmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str'. +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str'. +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next'. +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next'. +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str' +* from the character pointed to by 'p1_str'. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_Cmp (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str) +{ + CPU_INT16S cmp_val; + + + cmp_val = Str_Cmp_N(p1_str, + p2_str, + DEF_INT_CPU_U_MAX_VAL); + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_Cmp_N() +* +* Description : Determine if two strings are identical for up to a maximum number of characters. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* len_max Maximum number of characters to compare (see Note #3d). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' states that : +* +* (1) "The strncmp() function shall compare ... the array pointed to by 's1' ('p1_str') +* to the array pointed to by 's2' ('p2_str)" ... +* (2) but "not more than 'n' ('len_max') bytes" of either array. +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : RETURN VALUE' states that +* "upon successful completion, strncmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' adds that +* "the sign of a non-zero return value is determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str'. +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str'. +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next'. +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next'. +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str' +* from the character pointed to by 'p1_str'. +* +* (d) (1) 'len_max' passed a zero length. +* (A) Zero-length strings identical; 0 returned. +* +* (2) First 'len_max' number of characters identical. +* (A) Strings identical; 0 returned. +* +* See also Note #2a2. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_Cmp_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *p1_str_cmp; + const CPU_CHAR *p2_str_cmp; + const CPU_CHAR *p1_str_cmp_next; + const CPU_CHAR *p2_str_cmp_next; + CPU_INT16S cmp_val; + CPU_SIZE_T cmp_len; + + + if (len_max < 1) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */ + return (0); + } + + if (p1_str == (const CPU_CHAR *)0) { + if (p2_str == (const CPU_CHAR *)0) { + return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */ + } + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)(*p2_str)); + return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/ + } + if (p2_str == (const CPU_CHAR *)0) { + cmp_val = (CPU_INT16S)(*p1_str); + return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/ + } + + + p1_str_cmp = p1_str; + p2_str_cmp = p2_str; + p1_str_cmp_next = p1_str_cmp; + p2_str_cmp_next = p2_str_cmp; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len = 0u; + + while ((*p1_str_cmp == *p2_str_cmp) && /* Cmp strs until non-matching chars (see Note #3c) ... */ + (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */ + ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2). */ + ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) && + ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */ + p1_str_cmp++; + p2_str_cmp++; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len++; + } + + + if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */ + return (0); /* ... rtn 0 (see Note #3d2A). */ + } + + if (*p1_str_cmp != *p2_str_cmp) { /* If strs NOT identical, ... */ + /* ... calc & rtn char diff (see Note #3c1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)(*p1_str_cmp) - (CPU_INT16S)(*p2_str_cmp)); + + } else if (*p1_str_cmp == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */ + cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */ + + } else { + if (p1_str_cmp_next == (const CPU_CHAR *)0) { + if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */ + cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */ + } else { /* If p1_str_cmp_next NULL, ... */ + /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)(*p2_str_cmp_next)); + } + } else { /* If p2_str_cmp_next NULL, ... */ + cmp_val = (CPU_INT16S)(*p1_str_cmp_next); /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */ + } + } + + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_CmpIgnoreCase() +* +* Description : Determine if two strings are identical, ignoring case. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : DESCRIPTION' states that : +* +* (1) (A) "The strcasecmp() function shall compare ... the string pointed to by 's1' +* ('p1_str') to the string pointed to by 's2' ('p2_str')" ... +* (B) "ignoring differences in case". +* +* (2) "strcasecmp() ... shall behave as if the strings had been converted to lowercase +* and then a byte comparison performed." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : RETURN VALUE' states that +* "upon successful completion, strcasecmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str', converted +* to lower case (see Note #2a2). +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str', converted +* to lower case (see Note #2a2). +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str', +* converted to lower case, from the character pointed to by 'p1_str', converted +* to lower case. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_CmpIgnoreCase (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str) +{ + CPU_INT16S cmp_val; + + + cmp_val = Str_CmpIgnoreCase_N(p1_str, + p2_str, + DEF_INT_CPU_U_MAX_VAL); + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_CmpIgnoreCase_N() +* +* Description : Determine if two strings are identical for up to a maximum number of characters, +* ignoring case. +* +* Argument(s) : p1_str Pointer to first string (see Note #1). +* +* p2_str Pointer to second string (see Note #1). +* +* len_max Maximum number of characters to compare (see Note #3d). +* +* Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d). +* +* Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c). +* +* Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c). +* +* See also Note #2b. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : DESCRIPTION' states that : +* +* (1) (A) "The strncasecmp() function shall compare ... the string pointed to by 's1' +* ('p1_str') to the string pointed to by 's2' ('p2_str')" ... +* (B) "ignoring differences in case" ... +* (C) but "not more than 'n' ('len_max') bytes" of either string. +* +* (2) "strncasecmp() shall behave as if the strings had been converted to lowercase +* and then a byte comparison performed." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : RETURN VALUE' states that +* "upon successful completion, strncasecmp() shall return an integer greater than, +* equal to, or less than 0". +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the +* sign of a non-zero return value shall be determined by the sign of the difference +* between the values of the first pair of bytes ... that differ in the strings +* being compared". +* +* (3) String comparison terminates when : +* +* (a) (1) (A) BOTH string pointer(s) are passed NULL pointers. +* (1) NULL strings identical; 0 returned. +* +* (B) (1) 'p1_str' passed a NULL pointer. +* (a) Return negative value of character pointed to by 'p2_str', converted +* to lower case (see Note #2a2). +* +* (2) 'p2_str' passed a NULL pointer. +* (a) Return positive value of character pointed to by 'p1_str', converted +* to lower case (see Note #2a2). +* +* (2) (A) BOTH strings point to NULL. +* (1) Strings overlap with NULL address. +* (2) Strings identical up to but NOT beyond or including the NULL address; +* 0 returned. +* +* (B) (1) 'p1_str_cmp_next' points to NULL. +* (a) 'p1_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return negative value of character pointed to by 'p2_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (2) 'p2_str_cmp_next' points to NULL. +* (a) 'p2_str' overlaps with NULL address. +* (b) Strings compared up to but NOT beyond or including the NULL address. +* (c) Return positive value of character pointed to by 'p1_str_cmp_next', +* converted to lower case (see Note #2a2). +* +* (b) Terminating NULL character found in both strings. +* (1) Strings identical; 0 returned. +* (2) Only one NULL character test required in conditional since previous condition +* tested character equality. +* +* (c) Non-matching characters found. +* (1) Return signed-integer difference of the character pointed to by 'p2_str', +* converted to lower case, from the character pointed to by 'p1_str', converted +* to lower case. +* +* (d) (1) 'len_max' passed a zero length. +* (A) Zero-length strings identical; 0 returned. +* +* (2) First 'len_max' number of characters identical. +* (A) Strings identical; 0 returned. +* +* See also Note #2a1C. +* +* (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison +* return value, 'CPU_CHAR' native data type size MUST be 8-bit. +********************************************************************************************************* +*/ + +CPU_INT16S Str_CmpIgnoreCase_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max) +{ + const CPU_CHAR *p1_str_cmp; + const CPU_CHAR *p2_str_cmp; + const CPU_CHAR *p1_str_cmp_next; + const CPU_CHAR *p2_str_cmp_next; + CPU_CHAR char_1; + CPU_CHAR char_2; + CPU_INT16S cmp_val; + CPU_SIZE_T cmp_len; + + + if (len_max < 1) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */ + return (0); + } + + if (p1_str == (const CPU_CHAR *)0) { + if (p2_str == (const CPU_CHAR *)0) { + return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */ + } + char_2 = ASCII_ToLower(*p2_str); + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)char_2); + return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/ + } + if (p2_str == (const CPU_CHAR *)0) { + char_1 = ASCII_ToLower(*p1_str); + cmp_val = (CPU_INT16S)char_1; + return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/ + } + + + p1_str_cmp = p1_str; + p2_str_cmp = p2_str; + p1_str_cmp_next = p1_str_cmp; + p2_str_cmp_next = p2_str_cmp; + p1_str_cmp_next++; + p2_str_cmp_next++; + char_1 = ASCII_ToLower(*p1_str_cmp); + char_2 = ASCII_ToLower(*p2_str_cmp); + cmp_len = 0u; + + while (( char_1 == char_2) && /* Cmp strs until non-matching chars (see Note #3c) ... */ + (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */ + ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2). */ + ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) && + ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */ + p1_str_cmp++; + p2_str_cmp++; + p1_str_cmp_next++; + p2_str_cmp_next++; + cmp_len++; + char_1 = ASCII_ToLower(*p1_str_cmp); + char_2 = ASCII_ToLower(*p2_str_cmp); + } + + + if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */ + return (0); /* ... rtn 0 (see Note #3d2A). */ + } + + if (char_1 != char_2) { /* If strs NOT identical, ... */ + /* ... calc & rtn char diff (see Note #3c1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)char_1 - (CPU_INT16S)char_2); + + } else if (char_1 == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */ + cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */ + + } else { + if (p1_str_cmp_next == (const CPU_CHAR *)0) { + if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */ + cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */ + } else { /* If p1_str_cmp_next NULL, ... */ + char_2 = ASCII_ToLower(*p2_str_cmp_next); + /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */ + cmp_val = (CPU_INT16S)((CPU_INT16S)0 - (CPU_INT16S)char_2); + } + } else { /* If p2_str_cmp_next NULL, ... */ + char_1 = ASCII_ToLower(*p1_str_cmp_next); + cmp_val = (CPU_INT16S)char_1; /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */ + } + } + + + return (cmp_val); +} + + +/* +********************************************************************************************************* +* Str_Char() +* +* Description : Search string for first occurrence of specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* srch_char Search character. +* +* Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that : +* +* (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that +* "upon completion, strchr() shall return" : +* +* (1) "a pointer to the byte," ... +* (2) "or a null pointer if the byte was not found." +* (A) #### Although NO strchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to first occurrence of search character in search string +* (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char (const CPU_CHAR *pstr, + CPU_CHAR srch_char) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_N(pstr, + DEF_INT_CPU_U_MAX_VAL, + srch_char); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_N() +* +* Description : Search string for first occurrence of specific character, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* srch_char Search character. +* +* Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that : +* +* (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that +* "upon completion, strchr() shall return" : +* +* (1) "a pointer to the byte," ... +* (2) "or a null pointer if the byte was not found." +* (A) #### Although NO strchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (c) Ideally, the 'len_max' argument would be the last argument in this function's +* argument list for consistency with all other custom string library functions. +* However, the 'len_max' argument is sequentially ordered as the second argument +* to comply with most standard library's strnchr() argument list. +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to first occurrence of search character in search string +* (see Note #2a1). +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within first 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char) +{ + const CPU_CHAR *pstr_char; + CPU_SIZE_T len_srch; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3e1). */ + return ((CPU_CHAR *)0); + } + + + pstr_char = pstr; + len_srch = 0u; + + while (( pstr_char != (const CPU_CHAR *) 0 ) && /* Srch str until NULL ptr [see Note #3b] ... */ + (*pstr_char != ( CPU_CHAR )'\0') && /* ... or NULL char (see Note #3c) ... */ + (*pstr_char != ( CPU_CHAR )srch_char) && /* ... or srch char found (see Note #3d); ... */ + ( len_srch < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3e). */ + pstr_char++; + len_srch++; + } + + if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + if (len_srch >= len_max) { /* Rtn NULL if srch char NOT found ... */ + return ((CPU_CHAR *)0); /* ... within max nbr of chars (see Note #3e1). */ + } + + if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */ + return ((CPU_CHAR *)0); + } + + + return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */ +} + + +/* +********************************************************************************************************* +* Str_Char_Last() +* +* Description : Search string for last occurrence of specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* srch_char Search character. +* +* Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that : +* +* (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that +* "upon successful completion, strrchr() shall return" : +* +* (1) "a pointer to the byte" ... +* (2) "or a null pointer if 'c' ('srch_char') does not occur in the string." +* (A) #### Although NO strrchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String searched from end to beginning. +* (1) Search character NOT found in search string; NULL pointer returned. +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to last occurrence of search character in search string +* (see Note #2a1). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Last (const CPU_CHAR *pstr, + CPU_CHAR srch_char) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_Last_N(pstr, + DEF_INT_CPU_U_MAX_VAL, + srch_char); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_Last_N() +* +* Description : Search string for last occurrence of specific character, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* srch_char Search character. +* +* Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1). +* +* Pointer to NULL, otherwise (see Note #2b2). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that : +* +* (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char') +* ... in the string pointed to by 's' ('pstr')." +* (2) "The terminating null byte is considered to be part of the string." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that +* "upon successful completion, strrchr() shall return" : +* +* (1) "a pointer to the byte" ... +* (2) "or a null pointer if 'c' ('srch_char') does not occur in the string." +* (A) #### Although NO strrchr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (c) Ideally, the 'len_max' argument would be the last argument in this function's +* argument list for consistency with all other custom string library functions. +* However, the 'len_max' argument is sequentially ordered as the second argument +* to comply with most standard library's strnrchr() argument list. +* +* See also 'Str_Char_N() Note #2c'. +* +* (3) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String searched from end to beginning. +* (1) Search character NOT found in search string; NULL pointer returned +* (see Note #2b2). +* (2) Applicable even if search character is the terminating NULL character +* (see Note #2a2). +* +* (d) Search character found. +* (1) Return pointer to last occurrence of search character in search string +* (see Note #2a1). +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within last 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Last_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char) +{ + const CPU_CHAR *pstr_char; + CPU_SIZE_T str_len_max; + CPU_SIZE_T str_len; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3e1). */ + return ((CPU_CHAR *)0); + } + + + pstr_char = pstr; + str_len_max = len_max - sizeof(""); /* Str len adj'd for NULL char len. */ + str_len = Str_Len_N(pstr_char, str_len_max); + pstr_char += str_len; + + if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */ + return ((CPU_CHAR *)0); + } + + while (( pstr_char != pstr) && /* Srch str from end until beginning (see Note #3c) ... */ + (*pstr_char != srch_char)) { /* ... until srch char found (see Note #3d). */ + pstr_char--; + } + + + if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */ + return ((CPU_CHAR *)0); + } + + + return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */ +} + + +/* +********************************************************************************************************* +* Str_Char_Replace() +* +* Description : Search string for specific character and replace it by another specific character. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* char_srch Search character. +* +* char_replace Replace character. +* +* Return(s) : Pointer to string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer modified. +* +* (2) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (2) Applicable even if search character is the terminating NULL character +* +* (d) Search character found. +* (1) Replace character found by the specified character. +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Replace (CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Char_Replace_N(pstr, + char_srch, + char_replace, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Char_Replace_N() +* +* Description : Search string for specific character and replace it by another specific character, up to +* a maximum number of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* char_srch Search character. +* +* char_replace Replace character. +* +* len_max Maximum number of characters to search (see Notes #2c & #3e). +* +* Return(s) : Pointer to string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer modified. +* +* (2) String search terminates when : +* +* (a) String pointer passed a NULL pointer. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer points to NULL. +* (1) String overlaps with NULL address; NULL pointer returned. +* +* (c) String's terminating NULL character found. +* (1) Search character NOT found in search string; NULL pointer returned +* (2) Applicable even if search character is the terminating NULL character +* +* (d) Search character found. +* (1) Replace character found by the specified character. +* +* (e) 'len_max' number of characters searched. +* (1) Search character NOT found in search string within first 'len_max' number +* of characters; NULL pointer returned. +* (2) 'len_max' number of characters MAY include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Char_Replace_N (CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace, + CPU_SIZE_T len_max) +{ + CPU_CHAR *pstr_char; + CPU_SIZE_T len; + + + if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #2a1). */ + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #2e1). */ + return ((CPU_CHAR *)0); + } + + pstr_char = pstr; + len = len_max; + + while (( pstr_char != (const CPU_CHAR *)0) && /* Srch str until NULL ptr [see Note #2b] ... */ + (*pstr_char != ASCII_CHAR_NULL ) && /* ... or NULL char (see Note #2c) ... */ + ( len > 0)) { /* ... or max nbr chars srch'd (see Note #2e). */ + + if (*pstr_char == char_srch) { + *pstr_char = char_replace; /* Replace char if srch char is found. */ + } + + pstr_char++; + len--; + } + + return (pstr); +} + + +/* +********************************************************************************************************* +* Str_Str() +* +* Description : Search string for first occurence of a specific search string. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* pstr_srch Pointer to search string (see Note #1). +* +* Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A). +* +* Pointer to string, if NULL search string (see Note #2b2). +* +* Pointer to NULL, otherwise (see Note #2b1B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that : +* +* (1) "The strstr() function shall locate the first occurrence in the string +* pointed to by 's1' ('pstr') of the sequence of bytes ... in the string +* pointed to by 's2' ('pstr_srch')" ... +* (2) "(excluding the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that : +* +* (1) "Upon successful completion, strstr() shall return" : +* (A) "a pointer to the located string" ... +* (B) "or a null pointer if the string is not found." +* (1) #### Although NO strstr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (2) "If 's2' ('pstr_srch') points to a string with zero length, the function +* shall return 's1' ('pstr')." +* +* (3) String search terminates when : +* +* (a) String pointer(s) are passed NULL pointers. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Search string length equal to zero. +* (1) No string search performed; string pointer returned (see Note #2b2). +* +* (d) Search string length greater than string length. +* (1) No string search performed; NULL pointer returned (see Note #2b1B). +* +* (e) Entire string has been searched. +* (1) Search string not found; NULL pointer returned (see Note #2b1B). +* +* (f) Search string found. +* (1) Return pointer to first occurrence of search string in string (see Note #2b1A). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Str (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch) +{ + CPU_CHAR *pstr_rtn; + + + pstr_rtn = Str_Str_N(pstr, + pstr_srch, + DEF_INT_CPU_U_MAX_VAL); + + return (pstr_rtn); +} + + +/* +********************************************************************************************************* +* Str_Str_N() +* +* Description : Search string for first occurence of a specific search string, up to a maximum number +* of characters. +* +* Argument(s) : pstr Pointer to string (see Note #1). +* +* pstr_srch Pointer to search string (see Note #1). +* +* len_max Maximum number of characters to search (see Note #3g). +* +* Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A). +* +* Pointer to string, if NULL search string (see Note #2b2). +* +* Pointer to NULL, otherwise (see Note #2b1B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffers NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that : +* +* (1) "The strstr() function shall locate the first occurrence in the string +* pointed to by 's1' ('pstr') of the sequence of bytes ... in the string +* pointed to by 's2' ('pstr_srch')" ... +* (2) "(excluding the terminating null byte)." +* +* (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that : +* +* (1) "Upon successful completion, strstr() shall return" : +* (A) "a pointer to the located string" ... +* (B) "or a null pointer if the string is not found." +* (1) #### Although NO strstr() specification states to return NULL for +* any other reason(s), NULL is also returned for any error(s). +* +* (2) "If 's2' ('pstr_srch') points to a string with zero length, the function +* shall return 's1' ('pstr')." +* +* (3) String search terminates when : +* +* (a) String pointer(s) are passed NULL pointers. +* (1) No string search performed; NULL pointer returned. +* +* (b) String pointer(s) point to NULL. +* (1) String buffer(s) overlap with NULL address; NULL pointer returned. +* +* (c) Search string length equal to zero. +* (1) No string search performed; string pointer returned (see Note #2b2). +* +* (d) Search string length greater than string length. +* (1) No string search performed; NULL pointer returned (see Note #2b1B). +* +* (e) Entire string has been searched. +* (1) Search string not found; NULL pointer returned (see Note #2b1B). +* (2) Maximum size of the search is defined as the subtraction of the +* search string length from the string length. +* +* (f) Search string found. +* (1) Return pointer to first occurrence of search string in string (see Note #2b1A). +* (2) Search string found via Str_Cmp_N(). +* +* (g) 'len_max' number of characters searched. +* (1) 'len_max' number of characters does NOT include terminating NULL character +* (see Note #2a2). +********************************************************************************************************* +*/ + +CPU_CHAR *Str_Str_N (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch, + CPU_SIZE_T len_max) +{ + CPU_SIZE_T str_len; + CPU_SIZE_T str_len_srch; + CPU_SIZE_T len_max_srch; + CPU_SIZE_T srch_len; + CPU_SIZE_T srch_ix; + CPU_BOOLEAN srch_done; + CPU_INT16S srch_cmp; + const CPU_CHAR *pstr_str; + const CPU_CHAR *pstr_srch_ix; + + /* Rtn NULL if str ptr(s) NULL (see Note #3a). */ + if (pstr == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + if (pstr_srch == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + if (len_max < 1) { /* Rtn NULL if srch len = 0 (see Note #3g). */ + return ((CPU_CHAR *)0); + } + + /* Lim max srch str len (to chk > str len). */ + len_max_srch = (len_max < DEF_INT_CPU_U_MAX_VAL) + ? (len_max + 1u) : DEF_INT_CPU_U_MAX_VAL; + + str_len = Str_Len_N(pstr, len_max); + str_len_srch = Str_Len_N(pstr_srch, len_max_srch); + if (str_len_srch < 1) { /* Rtn ptr to str if srch str len = 0 (see Note #2b2). */ + return ((CPU_CHAR *)pstr); + } + if (str_len_srch > str_len) { /* Rtn NULL if srch str len > str len (see Note #3d). */ + return ((CPU_CHAR *)0); + } + + /* Rtn NULL if NULL ptr found (see Note #3b1). */ + pstr_str = pstr + str_len; + if (pstr_str == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + pstr_str = pstr_srch + str_len_srch; + if (pstr_str == (const CPU_CHAR *)0) { + return ((CPU_CHAR *)0); + } + + srch_len = str_len - str_len_srch; /* Calc srch len (see Note #3e2). */ + srch_ix = 0u; + + do { + pstr_srch_ix = (const CPU_CHAR *)(pstr + srch_ix); + srch_cmp = Str_Cmp_N(pstr_srch_ix, pstr_srch, str_len_srch); + srch_done = (srch_cmp == 0) ? DEF_YES : DEF_NO; + srch_ix++; + } while ((srch_done == DEF_NO) && (srch_ix <= srch_len)); + + + if (srch_cmp != 0) { /* Rtn NULL if srch str NOT found (see Note #3e2). */ + return ((CPU_CHAR *)0); + } + + return ((CPU_CHAR *)pstr_srch_ix); /* Else rtn ptr to found srch str (see Note #3f1). */ +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32U() +* +* Description : Format 32-bit unsigned integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* The following may be used to specify the number of digits to format : +* +* DEF_INT_32U_NBR_DIG_MIN Minimum number of 32-bit unsigned digits +* DEF_INT_32U_NBR_DIG_MAX Maximum number of 32-bit unsigned digits +* +* nbr_base Base of number to format (see Note #2). +* +* The following may be used to specify the number base : +* +* DEF_NBR_BASE_BIN Base 2 +* DEF_NBR_BASE_OCT Base 8 +* DEF_NBR_BASE_DEC Base 10 +* DEF_NBR_BASE_HEX Base 16 +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = 23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #6a +* +* (b) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #6b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters is equal to the requested +* number of integer digits to format ('nbr_dig'). +* +* Example : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 'NUL' terminator) characters +* +* (6) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +CPU_CHAR *Str_FmtNbr_Int32U (CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + + + pstr_fmt = Str_FmtNbr_Int32(nbr, /* Fmt unsigned int into str. */ + nbr_dig, + nbr_base, + DEF_NO, + lead_char, + lower_case, + nul, + pstr); + + return (pstr_fmt); +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32S() +* +* Description : Format 32-bit signed integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* The following may be used to specify the number of digits to format : +* +* DEF_INT_32S_NBR_DIG_MIN + 1 Minimum number of 32-bit signed digits +* DEF_INT_32S_NBR_DIG_MAX + 1 Maximum number of 32-bit signed digits +* (plus 1 digit for possible negative sign) +* +* nbr_base Base of number to format (see Note #2). +* +* The following may be used to specify the number base : +* +* DEF_NBR_BASE_BIN Base 2 +* DEF_NBR_BASE_OCT Base 8 +* DEF_NBR_BASE_DEC Base 10 +* DEF_NBR_BASE_HEX Base 16 +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s). +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #6a +* +* (b) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #6b +* +* (c) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456 +* nbr_dig = 5 +* nbr_base = 10 +* +* pstr = "?????" See Note #6b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* +* nbr = -23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " -23456" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '0' +* +* pstr = "-0023456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '0' +* lower_case = DEF_NO +* +* pstr = "-000ABCD" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '#' +* +* pstr = "##-23456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '#' +* lower_case = DEF_YES +* +* pstr = "###-abcd" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 negative sign + +* 1 'NUL' terminator) characters +* +* (6) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +CPU_CHAR *Str_FmtNbr_Int32S (CPU_INT32S nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_INT32S nbr_fmt; + CPU_BOOLEAN nbr_neg; + + + if (nbr < 0) { /* If nbr neg, ... */ + nbr_fmt = -nbr; /* ... negate nbr. */ + nbr_neg = DEF_YES; + } else { + nbr_fmt = nbr; + nbr_neg = DEF_NO; + } + + pstr_fmt = Str_FmtNbr_Int32((CPU_INT32U)nbr_fmt, /* Fmt signed int into str. */ + nbr_dig, + nbr_base, + nbr_neg, + lead_char, + lower_case, + nul, + pstr); + + return (pstr_fmt); +} + + +/* +********************************************************************************************************* +* Str_FmtNbr_32() +* +* Description : Format number into a multi-digit character string. +* +* Argument(s) : nbr Number to format (see Note #1). +* +* nbr_dig Number of decimal digits to format (see Note #2). +* +* nbr_dp Number of decimal point digits to format. +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6d). +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s) [see Note #6c]. +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Application. +* +* Note(s) : (1) (a) The maximum accuracy for 32-bit floating-point numbers : +* +* +* Maximum Accuracy log [Internal-Base ^ (Number-Internal-Base-Digits)] +* 32-bit Floating-point Number = ----------------------------------------------------- +* log [External-Base] +* +* log [2 ^ 24] +* = -------------- +* log [10] +* +* < 7.225 Base-10 Digits +* +* where +* Internal-Base Internal number base of floating- +* point numbers (i.e. 2) +* External-Base External number base of floating- +* point numbers (i.e. 10) +* Number-Internal-Base-Digits Number of internal number base +* significant digits (i.e. 24) +* +* (b) Some CPUs' &/or compilers' floating-point implementations MAY further reduce the +* maximum accuracy. +* +* (2) (a) If the total number of digits to format ('nbr_dig + nbr_dp') is zero; then NO +* formatting is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 0 +* nbr_dp = 0 +* +* pstr = "" See Note #7a +* +* (b) (1) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456.789 +* nbr_dig = 3 +* nbr_dp = 2 +* +* pstr = "??????" See Note #7d +* +* (2) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 5 +* nbr_dp = 2 +* +* pstr = "????????" See Note #7d +* +* (3) If the number to format ('nbr') is negative but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is one +* but the number of decimal point digits to format ('nbr_dp') is zero; then +* an invalid string is formatted instead of truncating the negative sign. +* +* Example : +* +* nbr = -0.7895 +* nbr_dig = 1 +* nbr_dp = 0 +* +* pstr = "?" See Note #7d +* +* (4) (A) If the number to format ('nbr') is negative but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is +* zero but the number of decimal point digits to format ('nbr_dp') is non- +* zero; then the negative sign immediately prefixes the decimal point -- +* with NO decimal digits formatted, NOT even a single decimal digit of '0'. +* +* Example : +* +* nbr = -0.7895 +* nbr_dig = 0 +* nbr_dp = 2 +* +* pstr = "-.78" +* +* (B) If the number to format ('nbr') is positive but the number of significant +* integer digits is zero, & the number of digits to format ('nbr_dig') is +* zero but the number of decimal point digits to format ('nbr_dp') is non- +* zero; then a single decimal digit of '0' prefixes the decimal point. +* +* This '0' digit is used whenever a negative sign is not formatted (see +* Note #2b4A) so that the formatted string's decimal point is not floating, +* but fixed in the string as the 2nd character. +* +* Example : +* +* nbr = 0.7895 +* nbr_dig = 0 +* nbr_dp = 2 +* +* pstr = "0.78" +* +* (c) (1) If the total number of digits to format ('nbr_dig + nbr_dp') is greater than ... : +* +* (A) ... the maximum accuracy of the CPU's &/or compiler's 32-bit floating-point +* numbers, digits following all significantly-accurate digits of the number to +* format ('nbr') will be inaccurate; ... +* (B) ... the configured maximum accuracy ('LIB_STR_CFG_FP_MAX_NBR_DIG_SIG'), all +* digits or decimal places following all significantly-accurate digits of the +* number to format ('nbr') will be replaced & formatted with zeros ('0'). +* +* Example : +* +* nbr = 123456789.012345 +* nbr_dig = 9 +* nbr_dp = 6 +* LIB_STR_CFG_FP_MAX_NBR_DIG_SIG = 7 +* +* pstr = "123456700.000000" +* +* (2) Therefore, one or more least-significant digit(s) of the number to format ('nbr') +* MAY be rounded & not necessarily truncated due to the inaccuracy of the CPU's +* &/or compiler's floating-point implementation. +* +* See also Note #1. +* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a base-10 digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456.789 +* nbr_dig = 7 +* nbr_dp = 2 +* lead_char = ' ' +* +* pstr = " 23456.78" +* +* +* nbr = -23456.789 +* nbr_dig = 7 +* nbr_dp = 2 +* lead_char = ' ' +* +* pstr = " -23456.78" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Example : +* +* nbr = -23456.789 +* nbr_dig = 8 +* nbr_dp = 2 +* lead_char = '0' +* +* pstr = "-0023456.78" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456.789 +* nbr_dig = 8 +* nbr_dp = 2 +* lead_char = '#' +* +* pstr = "##-23456.78" +* +* (c) (1) If the integer value of the number to format is zero & ... +* (2) ... the number of digits to format is greater than one ... +* (3) ... OR the number is NOT negative, ... +* (4) ... but NO leading character available; ... +* (5) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* See also Note #2b4B. +* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 'nbr_dp' + +* 1 negative sign + +* 1 decimal point + +* 1 'NUL' terminator) characters +* +* (6) String format terminates when : +* +* (a) Format string pointer is passed a NULL pointer. +* (1) No string formatted; NULL pointer returned. +* +* (b) Total number of digits to format ('nbr_dig + nbr_dp') is zero. +* (1) NULL string formatted (see Note #7a); NULL pointer returned. +* +* (c) Number of digits to format ('nbr_dig') is less than number of significant +* integer digits of the number to format ('nbr'), including possible +* negative sign. +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (d) Lead character is NOT a valid, printable character (see Note #3a). +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (e) Number successfully formatted into character string array. +* +* (7) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits ('nbr_dig') & number of decimal point digits ('nbr_dp') to format : +* +* { (a) 0 (NULL string) , if 'nbr_dig' = 0 AND +* { 'nbr_dp' = 0 +* { +* { (b) 'nbr_dig' , if 'nbr_dig' > 0 AND +* { 'nbr_dp' = 0 +* Invalid string's { +* number of = { (c) ['nbr_dp' + , if 'nbr_dig' = 0 AND +* question marks { 1 (for decimal point) + 'nbr_dp' > 0 +* { 1 (for negative sign) ] +* { +* { (d) ['nbr_dig' + , if 'nbr_dig' > 0 AND +* { 'nbr_dp' + 'nbr_dp' > 0 +* { 1 (for decimal point) ] +* +********************************************************************************************************* +*/ + +#if (LIB_STR_CFG_FP_EN == DEF_ENABLED) +CPU_CHAR *Str_FmtNbr_32 (CPU_FP32 nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_dp, + CPU_CHAR lead_char, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_DATA i; + CPU_FP32 nbr_fmt; + CPU_FP32 nbr_log; + CPU_INT32U nbr_shiftd; + CPU_INT16U nbr_dig_max; + CPU_INT16U nbr_dig_sig = 0; + CPU_INT08U nbr_neg_sign; + CPU_INT08U dig_val; + CPU_FP32 dig_exp; + CPU_FP32 dp_exp; + CPU_BOOLEAN lead_char_dig; + CPU_BOOLEAN lead_char_fmtd = DEF_NO; + CPU_BOOLEAN lead_char_0; + CPU_BOOLEAN fmt_invalid; + CPU_BOOLEAN print_char; + CPU_BOOLEAN nbr_neg; + CPU_BOOLEAN nbr_neg_fmtd = DEF_NO; + + + /* ---------------- VALIDATE FMT ARGS ----------------- */ + if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */ + return ((CPU_CHAR *)0); + } + + dig_exp = 1.0f; + fmt_invalid = DEF_NO; + lead_char_0 = (lead_char == '0') ? DEF_YES : DEF_NO; /* Chk if lead char a '0' dig (see Note #3b2). */ + nbr_fmt = 0.0f; + nbr_neg = DEF_NO; + + if ((nbr_dig < 1) && (nbr_dp < 1)) { /* If nbr digs/dps = 0, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6b). */ + } + + if (lead_char != (CPU_CHAR)'\0') { + print_char = ASCII_IsPrint(lead_char); + if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */ + + } else if (lead_char != '0') { /* Chk lead char for non-0 dig. */ + lead_char_dig = ASCII_IsDig(lead_char); + if (lead_char_dig == DEF_YES) { /* If lead char non-0 dig (see Note #3a2A), ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */ + } + } + } + + + /* ----------------- PREPARE NBR FMT ------------------ */ + pstr_fmt = pstr; + + if (fmt_invalid == DEF_NO) { + if (nbr < 0.0f) { /* If nbr neg, ... */ + nbr_fmt = -nbr; /* ... negate nbr. */ + nbr_neg_sign = 1u; + nbr_neg = DEF_YES; + } else { + nbr_fmt = nbr; + nbr_neg_sign = 0u; + nbr_neg = DEF_NO; + } + + nbr_log = nbr_fmt; + nbr_dig_max = 0u; + while (nbr_log >= 1.0f) { /* While base-10 digs avail, ... */ + nbr_dig_max++; /* ... calc max nbr digs. */ + nbr_log /= 10.0f; + } + + if (((nbr_dig >= (nbr_dig_max + nbr_neg_sign)) || /* If req'd nbr digs >= (max nbr digs + neg sign) .. */ + (nbr_dig_max < 1)) && /* .. or NO nbr digs, .. */ + ((nbr_dig > 1) || /* .. but NOT [(req'd nbr dig = 1) AND .. */ + (nbr_dp > 0) || /* .. (req'd nbr dp = 0) AND .. */ + (nbr_neg == DEF_NO))) { /* .. ( nbr neg )] (see Note #2b3). */ + /* .. prepare nbr digs to fmt. */ + for (i = 1u; i < nbr_dig; i++) { + dig_exp *= 10.0f; + } + + nbr_neg_fmtd = DEF_NO; + nbr_dig_sig = 0u; + lead_char_fmtd = DEF_NO; + } else { /* Else if nbr trunc'd, ... */ + fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6c). */ + } + } + + + /* ------------------- FMT NBR STR -------------------- */ + for (i = nbr_dig; i > 0; i--) { /* Fmt str for desired nbr digs : */ + if (fmt_invalid == DEF_NO) { + if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) { /* If nbr sig digs < max, fmt str digs; ... */ + nbr_shiftd = (CPU_INT32U)(nbr_fmt / dig_exp); + if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */ + (i == 1u)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */ + /* ... calc & fmt dig val; ... */ + if ((nbr_neg == DEF_YES) && /* If nbr neg ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd; ... */ + + if (lead_char_fmtd == DEF_YES) { /* ... & if lead char(s) fmt'd, ... */ + pstr_fmt--; /* ... replace last lead char w/ ... */ + } + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b). */ + nbr_neg_fmtd = DEF_YES; + } + + if (nbr_shiftd > 0) { /* If shifted nbr > 0, ... */ + dig_val = (CPU_INT08U)(nbr_shiftd % 10u); + *pstr_fmt++ = (CPU_CHAR )(dig_val + '0'); + + nbr_dig_sig++; /* ... inc nbr sig digs; ... */ + + } else if ((nbr_dig > 1) || /* ... else if req'd digs > 1 ... */ + (nbr_neg == DEF_NO)) { /* ... or non-neg nbr, ... */ + *pstr_fmt++ = '0'; /* ... fmt one '0' char (see Note #3c5). */ + } + + } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg ... */ + (lead_char_0 == DEF_YES) && /* ... & lead char a '0' dig ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */ + + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Note #3b); ... */ + nbr_neg_fmtd = DEF_YES; + + } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */ + *pstr_fmt++ = lead_char; /* ... fmt lead char. */ + lead_char_fmtd = DEF_YES; + } + + dig_exp /= 10.0f; /* Shift to next least-sig dig. */ + + } else { /* ... else append non-sig 0's (see Note #2c2). */ + *pstr_fmt++ = '0'; + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + + + if (nbr_dp > 0) { /* Fmt str for desired nbr dp : */ + if (nbr_dig < 1) { /* If NO digs fmt'd; ... */ + if (fmt_invalid == DEF_NO) { /* ... nbr fmt valid, ... */ + if ((nbr_neg == DEF_YES) && /* ... nbr neg ... */ + (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */ + *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b); ... */ + } else { /* ... else prepend 1 dig of '0' (see Note #3c5) ... */ + *pstr_fmt++ = '0'; + } + } else { /* ... else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + + if (fmt_invalid == DEF_NO) { /* If nbr fmt valid, ... */ + *pstr_fmt++ = '.'; /* ... append dp prior to dp conversion. */ + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + + dp_exp = 10.0f; + for (i = 0u; i < nbr_dp; i++) { + if (fmt_invalid == DEF_NO) { + /* If nbr sig digs < max, fmt str dps; ... */ + if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) { + nbr_shiftd = (CPU_INT32U)(nbr_fmt * dp_exp); + dig_val = (CPU_INT08U)(nbr_shiftd % 10u); + *pstr_fmt++ = (CPU_CHAR )(dig_val + '0'); + dp_exp *= 10.0f; /* Shift to next least-sig dp. */ + + if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */ + (nbr_dig_sig > 0)) { /* ... OR > 0 sig digs already fmt'd, ... */ + nbr_dig_sig++; /* ... inc nbr sig digs. */ + } + + } else { /* ... else append non-sig 0's (see Note #2c2). */ + *pstr_fmt++ = '0'; + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt++ = '?'; + } + } + } + + + if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */ + *pstr_fmt = (CPU_CHAR)'\0'; + } + + + if (fmt_invalid != DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6d). */ + return ((CPU_CHAR *)0); + } + + + return (pstr); /* Rtn ptr to fmt'd str (see Note #6e). */ +} +#endif + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32U() +* +* Description : Parse 32-bit unsigned integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type unsigned long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) However, it does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +* +* (2) Second, "they shall attempt to convert the subject sequence to an unsigned integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion [is] performed"; ... +* (2) "the value of 'str' ('pstr') [is] stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* (1) "If the correct value is outside the range of representable values, {ULONG_MAX} +* ... shall be returned." +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32U_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Invalid negative unsigned parse string : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " -12345678901234567890*123456" +* +********************************************************************************************************* +*/ + +CPU_INT32U Str_ParseNbr_Int32U (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base) +{ + CPU_INT32U nbr; + + + nbr = Str_ParseNbr_Int32( pstr, /* Parse/convert str ... */ + pstr_next, + nbr_base, + DEF_NO, /* ... as unsigned int (see Note #2a2). */ + (CPU_BOOLEAN *)0); + + return (nbr); +} + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32S() +* +* Description : Parse 32-bit signed integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* Return(s) : Parsed integer, if integer parsed with NO over- or underflow (see Note #2a3A). +* +* DEF_INT_32S_MIN_VAL, if integer parsed but negatively underflowed (see Note #2a3A1a). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but positively overflowed (see Note #2a3A1b). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Application. +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) However, it does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +* +* (2) Second, "they shall attempt to convert the subject sequence to an integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion is performed"; ... +* (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* +* (1) "If the correct value is outside the range of representable values", either +* of the following "shall be returned" : +* (a) "{LONG_MIN}" or ... +* (b) "{LONG_MAX}" +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Parse string integer underflow : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MIN_VAL +* pstr_next = "*123456" +* +********************************************************************************************************* +*/ + +CPU_INT32S Str_ParseNbr_Int32S (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base) +{ + CPU_INT32S nbr; + CPU_INT32U nbr_abs; + CPU_BOOLEAN nbr_neg; + + + nbr_abs = Str_ParseNbr_Int32(pstr, /* Parse/convert str ... */ + pstr_next, + nbr_base, + DEF_YES, /* ... as signed int (see Note #2a2). */ + &nbr_neg); + + if (nbr_neg == DEF_NO) { /* Chk for neg nbr & ovf/undf (see Note #2a3A1). */ + nbr = (nbr_abs > (CPU_INT32U) DEF_INT_32S_MAX_VAL) ? (CPU_INT32S)DEF_INT_32S_MAX_VAL + : (CPU_INT32S)nbr_abs; + } else { + nbr = (nbr_abs > (CPU_INT32U)-DEF_INT_32S_MIN_VAL_ONES_CPL) ? (CPU_INT32S)DEF_INT_32S_MIN_VAL + : -(CPU_INT32S)nbr_abs; + } + + return (nbr); +} + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* Str_FmtNbr_Int32() +* +* Description : Format 32-bit integer into a multi-digit character string. +* +* Argument(s) : nbr Number to format. +* +* nbr_dig Number of digits to format (see Note #1). +* +* nbr_base Base of number to format (see Note #2). +* +* nbr_neg Indicates whether number to format is negative : +* ------- +* DEF_NO Number is non-negative. +* DEF_YES Number is negative. +* +* Argument validated in Str_FmtNbr_Int32U(), +* Str_FmtNbr_Int32S(). +* +* lead_char Prepend leading character (see Note #3) : +* +* '\0' Do NOT prepend leading character to string. +* Printable character Prepend leading character to string. +* Unprintable character Format invalid string (see Note #6e). +* +* lower_case Format alphabetic characters (if any) in lower case : +* +* DEF_NO Format alphabetic characters in upper case. +* DEF_YES Format alphabetic characters in lower case. +* +* nul Append terminating NULL-character (see Note #4) : +* +* DEF_NO Do NOT append terminating NULL-character to string. +* DEF_YES Append terminating NULL-character to string. +* +* pstr Pointer to character array to return formatted number string (see Note #5). +* +* Return(s) : Pointer to formatted string, if NO error(s) [see Note #6f]. +* +* Pointer to NULL, otherwise. +* +* Caller(s) : Str_FmtNbr_Int32U(), +* Str_FmtNbr_Int32S(). +* +* Note(s) : (1) (a) The maximum number of digits to format for 32-bit integer numbers : +* +* +* Maximum Number of [ log (Number) ] +* 32-bit Integer Digits = floor [ -------------- + 1 ] +* to Format [ log (Base) ] +* +* where +* Number Number to format +* Base Base of number to format +* +* (b) (1) If the number of digits to format ('nbr_dig') is zero; then NO formatting +* is performed except possible NULL-termination of the string (see Note #4). +* +* Example : +* +* nbr = -23456 +* nbr_dig = 0 +* nbr_base = 10 +* +* pstr = "" See Note #7a +* +* (2) If the number of digits to format ('nbr_dig') is less than the number of +* significant integer digits of the number to format ('nbr'); then an invalid +* string is formatted instead of truncating any significant integer digits. +* +* Example : +* +* nbr = 23456 +* nbr_dig = 3 +* nbr_base = 10 +* +* pstr = "???" See Note #7b +* +* (3) If the number to format ('nbr') is negative but the number of digits to format +* ('nbr_dig') is equal to the number of significant integer digits of the number +* to format ('nbr'); then an invalid string is formatted instead of truncating +* the negative sign. +* +* Example : +* +* nbr = -23456 +* nbr_dig = 5 +* nbr_base = 10 +* +* pstr = "?????" See Note #7b +* +* (2) The number's base MUST be between 2 & 36, inclusive. +* +* (3) Leading character option prepends leading characters prior to the first non-zero digit. +* +* (a) (1) Leading character MUST be a printable ASCII character. +* +* (2) (A) Leading character MUST NOT be a number base digit, ... +* (B) with the exception of '0'. +* +* (b) (1) The number of leading characters is such that the total number of significant +* integer digits plus the number of leading characters plus possible negative +* sign character is equal to the requested number of integer digits to format +* ('nbr_dig'). +* +* Examples : +* +* nbr = 23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " 23456" +* +* +* nbr = -23456 +* nbr_dig = 7 +* nbr_base = 10 +* lead_char = ' ' +* +* pstr = " -23456" +* +* (2) (A) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is a '0' digit; then the negative sign character +* prefixes all leading characters prior to the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '0' +* +* pstr = "-0023456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '0' +* lower_case = DEF_NO +* +* pstr = "-000ABCD" +* +* (B) If the number to format ('nbr') is negative AND the leading character +* ('lead_char') is NOT a '0' digit; then the negative sign character +* immediately prefixes the most significant digit of the formatted number. +* +* Examples : +* +* nbr = -23456 +* nbr_dig = 8 +* nbr_base = 10 +* lead_char = '#' +* +* pstr = "##-23456" +* +* +* nbr = -43981 +* nbr_dig = 8 +* nbr_base = 16 +* lead_char = '#' +* lower_case = DEF_YES +* +* pstr = "###-abcd" +* +* (c) (1) If the value of the number to format is zero ... +* (2) ... & the number of digits to format is non-zero, ... +* (3) ... but NO leading character available; ... +* (4) ... then one digit of '0' value is formatted. +* +* This is NOT a leading character; but a single integer digit of '0' value. +* +* (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character +* array formatting. +* +* (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character +* terminate option DISABLED will cause character string run-on. +* +* (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller. +* +* (b) To prevent character buffer overrun : +* +* Character array size MUST be >= ('nbr_dig' + +* 1 negative sign + +* 1 'NUL' terminator) characters +* +* (6) String format terminates when : +* +* (a) Format string pointer is passed a NULL pointer. +* (1) No string formatted; NULL pointer returned. +* +* (b) Number of digits to format ('nbr_dig') is zero. +* (1) NULL string formatted (see Note #7a); NULL pointer returned. +* +* (c) Number of digits to format ('nbr_dig') is less than number of significant +* integer digits of the number to format ('nbr'), including possible +* negative sign. +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (d) Base is passed an invalid base (see Note #2). +* (1) Invalid string format performed; NULL pointer returned. +* +* (e) Lead character is NOT a valid, printable character (see Note #3a). +* (1) Invalid string formatted (see Note #7); NULL pointer returned. +* +* (f) Number successfully formatted into character string array. +* +* (7) For any unsuccessful string format or error(s), an invalid string of question marks +* ('?') will be formatted, where the number of question marks is determined by the +* number of digits to format ('nbr_dig') : +* +* Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0 +* number of = { +* question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0 +* +********************************************************************************************************* +*/ + +static CPU_CHAR *Str_FmtNbr_Int32 (CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_neg, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr) +{ + CPU_CHAR *pstr_fmt; + CPU_DATA i; + CPU_INT32U nbr_fmt = 0; + CPU_INT32U nbr_log; + CPU_INT08U nbr_dig_max; + CPU_INT08U nbr_dig_min; + CPU_INT08U nbr_dig_fmtd = 0; + CPU_INT08U nbr_neg_sign; + CPU_INT08U nbr_lead_char; + CPU_INT08U dig_val; + CPU_INT08U lead_char_delta_0; + CPU_INT08U lead_char_delta_a; + CPU_BOOLEAN lead_char_dig; + CPU_BOOLEAN lead_char_0; + CPU_BOOLEAN fmt_valid = DEF_YES; + CPU_BOOLEAN print_char; + CPU_BOOLEAN nbr_neg_fmtd = DEF_NO; + + + /* ---------------- VALIDATE FMT ARGS ----------------- */ + if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */ + return ((CPU_CHAR *)0); + } + + if (nbr_dig < 1) { /* If nbr digs = 0, ... */ + fmt_valid = DEF_NO; /* ... fmt valid str (see Note #6b). */ + } + /* If invalid base, ... */ + if ((nbr_base < 2u) || + (nbr_base > 36u)) { + fmt_valid = DEF_NO; /* ... fmt valid str (see Note #6d). */ + } + + if (lead_char != (CPU_CHAR)'\0') { + print_char = ASCII_IsPrint(lead_char); + if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */ + fmt_valid = DEF_NO; /* ... fmt valid str (see Note #6e). */ + + } else if (lead_char != '0') { /* Chk lead char for non-0 nbr base dig. */ + lead_char_delta_0 = (CPU_INT08U)(lead_char - '0'); + if (lower_case != DEF_YES) { + lead_char_delta_a = (CPU_INT08U)(lead_char - 'A'); + } else { + lead_char_delta_a = (CPU_INT08U)(lead_char - 'a'); + } + + lead_char_dig = (((nbr_base <= 10u) && (lead_char_delta_0 < nbr_base)) || + ((nbr_base > 10u) && ((lead_char_delta_0 < 10u) || + (lead_char_delta_a < (nbr_base - 10u))))) ? DEF_YES : DEF_NO; + + if (lead_char_dig == DEF_YES) { /* If lead char non-0 nbr base dig (see Note #3a2A), ...*/ + fmt_valid = DEF_NO; /* ... fmt valid str (see Note #6e). */ + } + } else { + /* Empty Else Statement */ + } + } + + + /* ----------------- PREPARE NBR FMT ------------------ */ + pstr_fmt = pstr; + lead_char_0 = DEF_NO; + + if (fmt_valid == DEF_YES) { + nbr_fmt = nbr; + nbr_log = nbr; + nbr_dig_max = 1u; + while (nbr_log >= nbr_base) { /* While nbr base digs avail, ... */ + nbr_dig_max++; /* ... calc max nbr digs. */ + nbr_log /= nbr_base; + } + + nbr_neg_sign = (nbr_neg == DEF_YES) ? 1u : 0u; + if (nbr_dig >= (nbr_dig_max + nbr_neg_sign)) { /* If req'd nbr digs >= (max nbr digs + neg sign), ... */ + nbr_neg_fmtd = DEF_NO; + nbr_dig_min = DEF_MIN(nbr_dig_max, nbr_dig); + /* ... calc nbr digs to fmt & nbr lead chars. */ + if (lead_char != (CPU_CHAR)'\0') { + nbr_dig_fmtd = nbr_dig; + nbr_lead_char = nbr_dig - + (nbr_dig_min + nbr_neg_sign); + } else { + nbr_dig_fmtd = nbr_dig_min + nbr_neg_sign; + nbr_lead_char = 0u; + } + + if (nbr_lead_char > 0) { /* If lead chars to fmt, ... */ + lead_char_0 = (lead_char == '0') /* ... chk if lead char a '0' dig (see Note #3a2B). */ + ? DEF_YES : DEF_NO; + } + + } else { /* Else if nbr trunc'd, ... */ + fmt_valid = DEF_NO; /* ... fmt valid str (see Note #6c). */ + } + } + + if (fmt_valid == DEF_NO) { + nbr_dig_fmtd = nbr_dig; + } + + + /* ------------------- FMT NBR STR -------------------- */ + pstr_fmt += nbr_dig_fmtd; /* Start fmt @ least-sig dig. */ + + if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */ + *pstr_fmt = (CPU_CHAR)'\0'; + } + pstr_fmt--; + + + for (i = 0u; i < nbr_dig_fmtd; i++) { /* Fmt str for desired nbr digs : */ + if (fmt_valid == DEF_YES) { + if ((nbr_fmt > 0) || /* If fmt nbr > 0 ... */ + (i == 0u)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */ + /* ... calc & fmt dig val; ... */ + dig_val = (CPU_INT08U)(nbr_fmt % nbr_base); + if (dig_val < 10u) { + *pstr_fmt-- = (CPU_CHAR)(dig_val + '0'); + } else { + if (lower_case != DEF_YES) { + *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'A'); + } else { + *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'a'); + } + } + + nbr_fmt /= nbr_base; /* Shift to next more-sig dig. */ + + } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg AND ... */ + (((lead_char_0 == DEF_NO ) && /* ... lead char NOT a '0' dig ... */ + (nbr_neg_fmtd == DEF_NO )) || /* ... but neg sign NOT yet fmt'd OR ... */ + ((lead_char_0 != DEF_NO ) && /* ... lead char is a '0' dig ... */ + (i == (nbr_dig_fmtd - 1u))))) { /* ... & on most-sig dig to fmt, ... */ + + *pstr_fmt-- = '-'; /* ... prepend neg sign (see Note #3b); ... */ + nbr_neg_fmtd = DEF_YES; + + } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */ + *pstr_fmt-- = lead_char; /* ... fmt lead char. */ + } else { + /* Empty Else Statement */ + } + + } else { /* Else fmt '?' for invalid str (see Note #7). */ + *pstr_fmt-- = '?'; + } + } + + + if (fmt_valid == DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6e). */ + return ((CPU_CHAR *)0); + } + + + return (pstr); /* Rtn ptr to fmt'd str (see Note #6f). */ +} + + +/* +********************************************************************************************************* +* Str_ParseNbr_Int32() +* +* Description : Parse 32-bit integer from string. +* +* Argument(s) : pstr Pointer to string (see Notes #1 & #2a). +* +* pstr_next Optional pointer to a variable to ... : +* +* (a) Return a pointer to first character following the integer string, +* if NO error(s) [see Note #2a2B2]; +* (b) Return a pointer to 'pstr', +* otherwise (see Note #2a2A2). +* +* nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1). +* +* nbr_signed Indicates whether number to parse is signed : +* +* DEF_NO Number is unsigned. +* DEF_YES Number is signed. +* +* pnbr_neg Pointer to a variable to return if the parsed (signed) number is negative : +* +* DEF_NO Number is non-negative. +* DEF_YES Number is negative. +* +* Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A). +* +* DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1). +* +* 0, otherwise (see Note #2a3B). +* +* Caller(s) : Str_ParseNbr_Int32U(), +* Str_ParseNbr_Int32S(). +* +* Note(s) : (1) String buffer NOT modified. +* +* (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these +* functions shall convert the initial portion of the string pointed to by 'str' ('pstr') +* to a type long ... representation" : +* +* (1) "First, they decompose the input string into three parts" : +* +* (A) "An initial, possibly empty, sequence of white-space characters [as specified +* by isspace()]." +* +* (1) "The subject sequence is defined as the longest initial subsequence of the +* input string, starting with the first non-white-space character that is of +* the expected form. The subject sequence shall contain no characters if the +* input string is empty or consists entirely of white-space characters." +* +* (B) (1) "A subject sequence interpreted as an integer represented in some radix +* determined by the value of 'base' ('nbr_base')" : +* +* (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the +* subject sequence is that of a decimal constant, octal constant, or +* hexadecimal constant" : +* +* (1) "A decimal constant begins with a non-zero digit, and consists of a +* sequence of decimal digits." +* +* (2) "An octal constant consists of the prefix '0' optionally followed by +* a sequence of the digits '0' to '7' only." +* +* (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed +* by a sequence of the decimal digits and letters 'a' (or 'A') to 'f' +* (or 'F') with values 10 to 15 respectively." +* +* (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form +* of the subject sequence is a sequence of letters and digits representing +* an integer with the radix specified by 'base' ('nbr_base')" : +* +* (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are +* ascribed the values 10 to 35"; ... +* (B) "only letters whose ascribed values are less than that of base +* are permitted." +* +* (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or +* '0X' may optionally precede the sequence of letters and digits." +* +* (B) Although NO specification states that "if the value of 'base' +* ('nbr_base') is" 8, the '0' character "may optionally precede +* the sequence of letters and digits"; it seems reasonable to +* allow the '0' character to be optionally parsed. +* +* (2) "A subject sequence .... may be preceded by a '+' or '-' sign." +* +* (a) It does NOT seem reasonable to parse & convert a negative number +* integer string into an unsigned integer. However, a negative sign +* for an unsigned integer will automatically be parsed as an invalid +* character (see Note #2aC1). +* +* (C) (1) (a) "A final string of one or more unrecognized characters," ... +* (b) "including the terminating null byte of the input string" ... +* (2) "other than a sign or a permissible letter or digit." +* +* (2) Second, "they shall attempt to convert the subject sequence to an integer" : +* +* (A) "If the subject sequence is empty or does not have the expected form" : +* +* (1) "no conversion is performed"; ... +* (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr' +* ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer." +* +* (B) "If the subject sequence has the expected form" : +* +* (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters +* starting with the first digit shall be interpreted as an integer constant." +* +* (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be +* used as the base for conversion, ascribing to each letter its value as +* given above" (see Note #2a1B1b1A). +* +* (2) "A pointer to the final string shall be stored in the object pointed to by +* 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null +* pointer." +* +* (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that : +* +* (A) "Upon successful completion, these functions shall return the converted value." +* (1) "If the correct value is outside the range of representable values, {LONG_MIN} +* [or] {LONG_MAX} ... shall be returned." +* +* (B) "If no conversion could be performed, 0 shall be returned." +* +* (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* shall fail if" : +* +* (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported." +* +* (B) "[ERANGE] - The value to be returned is not representable." +* +* (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions +* may fail if" : +* +* (A) "[EINVAL] - No conversion could be performed." +* +* (3) Return integer value & next string pointer should be used to diagnose parse success or failure : +* +* (a) Valid parse string integer : +* +* pstr = " ABCDE xyz" +* nbr_base = 16 +* +* nbr = 703710 +* pstr_next = " xyz" +* +* +* (b) Invalid parse string integer : +* +* pstr = " ABCDE" +* nbr_base = 10 +* +* nbr = 0 +* pstr_next = pstr = " ABCDE" +* +* +* (c) Valid hexadecimal parse string integer : +* +* pstr = " 0xGABCDE" +* nbr_base = 16 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (d) Valid decimal parse string integer ('0x' prefix ignored +* following invalid hexadecimal characters) : +* +* pstr = " 0xGABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "xGABCDE" +* +* +* (e) Valid decimal parse string integer ('0' prefix ignored +* following invalid octal characters) : +* +* pstr = " 0GABCDE" +* nbr_base = 0 +* +* nbr = 0 +* pstr_next = "GABCDE" +* +* +* (f) Parse string integer overflow : +* +* pstr = " 12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32U_MAX_VAL +* pstr_next = "*123456" +* +* +* (g) Parse string integer underflow : +* +* pstr = " -12345678901234567890*123456" +* nbr_base = 10 +* +* nbr = DEF_INT_32S_MIN_VAL +* pstr_next = "*123456" +* +* +* (4) String parse terminates when : +* +* (a) Base passed an invalid base (see Note #2a1B1b). +* (1) No conversion performed; 0 returned. +* +* (b) (1) Parse string passed a NULL pointer OR empty integer sequence (see Note #2a2A). +* (A) No conversion performed; 0 returned. +* +* (2) Invalid parse string character found (see Note #2a1C). +* (A) Parsed integer returned. +* (B) 'pstr_next' points to invalid character. +* +* (3) Entire parse string converted (see Note #2a2B). +* (A) Parsed integer returned. +* (B) 'pstr_next' points to terminating NULL character. +* +* (5) Pointers to variables that return values MUST be initialized PRIOR to all other +* validation or function handling in case of any error(s). +********************************************************************************************************* +*/ + +static CPU_INT32U Str_ParseNbr_Int32 (const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base, + CPU_BOOLEAN nbr_signed, + CPU_BOOLEAN *pnbr_neg) +{ + const CPU_CHAR *pstr_parse; + const CPU_CHAR *pstr_parse_nbr; + CPU_CHAR *pstr_parse_unused; + CPU_CHAR parse_char; + CPU_INT08U parse_dig; + CPU_INT32U nbr; + CPU_BOOLEAN nbr_neg_unused; + CPU_BOOLEAN nbr_dig; + CPU_BOOLEAN nbr_alpha; + CPU_BOOLEAN nbr_hex; + CPU_BOOLEAN nbr_hex_lower; + CPU_BOOLEAN whitespace; + CPU_BOOLEAN neg; + CPU_BOOLEAN ovf; + CPU_BOOLEAN done; + + /* --------------- VALIDATE PARSE ARGS ---------------- */ + if (pstr_next == (CPU_CHAR **) 0) { /* If NOT avail, ... */ + pstr_next = (CPU_CHAR **)&pstr_parse_unused; /* ... re-cfg NULL rtn ptr to unused local var. */ + (void)pstr_parse_unused; /* Prevent possible 'variable unused' warning. */ + } + *pstr_next = (CPU_CHAR *)pstr; /* Init rtn str for err (see Note #5). */ + + if (pnbr_neg == (CPU_BOOLEAN *) 0) { /* If NOT avail, ... */ + pnbr_neg = (CPU_BOOLEAN *)&nbr_neg_unused; /* ... re-cfg NULL rtn ptr to unused local var. */ + (void)nbr_neg_unused; /* Prevent possible 'variable unused' warning. */ + } + *pnbr_neg = DEF_NO; /* Init nbr neg for err (see Note #5). */ + + + if (pstr == (CPU_CHAR *)0) { /* Rtn zero if str ptr NULL (see Note #4b1). */ + return (0u); + } + /* Rtn zero if invalid base (see Note #4a). */ + if ((nbr_base == 1u) || + (nbr_base > 36u)) { + return (0u); + } + + + /* ------------- IGNORE PRECEDING CHAR(S) ------------- */ + pstr_parse = pstr; /* Save ptr to init'l str for err (see Note #2a2A2). */ + + whitespace = ASCII_IsSpace(*pstr_parse); + while (whitespace == DEF_YES) { /* Ignore initial white-space char(s) [see Note #2a1A]. */ + pstr_parse++; + whitespace = ASCII_IsSpace(*pstr_parse); + } + + switch (*pstr_parse) { + case '+': /* Ignore pos sign (see Note #2a1B2). */ + pstr_parse++; + neg = DEF_NO; + break; + + + case '-': /* Validate neg sign (see Note #2a1B2a). */ + if (nbr_signed == DEF_YES) { + pstr_parse++; + } + neg = DEF_YES; + break; + + + default: + neg = DEF_NO; + break; + } + + + /* --------- IGNORE NBR BASE PRECEDING CHAR(S) -------- */ + pstr_parse_nbr = pstr_parse; /* Save ptr to str's nbr (see Note #2a1A1). */ + + switch (nbr_base) { + case 0u: /* Determine unspecified nbr base (see Notes #2a1B1a). */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */ + switch (*pstr_parse) { + case 'x': /* For '0x' prefix, ... */ + case 'X': + nbr_base = 16u; /* ... set nbr base = 16 (see Note #2a1B1a3). */ + parse_char = (CPU_CHAR)(*(pstr_parse + 1)); + nbr_hex = ASCII_IsDigHex(parse_char); + if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */ + pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */ + } + break; + + + default: /* For '0' prefix, ... */ + nbr_base = 8u; /* ... set nbr base = 8 (see Note #2a1B1a2). */ + break; + } + + } else { /* For non-'0' prefix, ... */ + nbr_base = 10u; /* ... set nbr base = 10 (see Note #2a1B1a1). */ + } + break; + + + case 8u: /* See Note #2a1B1a2. */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2B). */ + } + break; + + + case 16u: /* See Note #2a1B1a3. */ + if (*pstr_parse == '0') { /* If avail, ... */ + pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */ + switch (*pstr_parse) { + case 'x': + case 'X': + parse_char = (CPU_CHAR)(*(pstr_parse + 1)); + nbr_hex = ASCII_IsDigHex(parse_char); + if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */ + pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */ + } + break; + + + default: + break; + } + } + break; + + + default: /* See Note #2a1B1b. */ + break; + } + + + /* ------------------ PARSE INT STR ------------------- */ + nbr = 0u; + ovf = DEF_NO; + done = DEF_NO; + + while (done == DEF_NO) { /* Parse str for desired nbr base digs (see Note #2a2). */ + parse_char = (CPU_CHAR)*pstr_parse; + nbr_alpha = ASCII_IsAlphaNum(parse_char); + if (nbr_alpha == DEF_YES) { /* If valid alpha num nbr dig avail, ... */ + /* ... convert parse char into nbr dig. */ + nbr_dig = ASCII_IsDig(parse_char); + if (nbr_dig == DEF_YES) { + parse_dig = (CPU_INT08U)(parse_char - '0'); + } else { + nbr_hex_lower = ASCII_IsLower(parse_char); + if (nbr_hex_lower == DEF_YES) { + parse_dig = ((CPU_INT08U)(parse_char - 'a') + 10u); + } else { + parse_dig = ((CPU_INT08U)(parse_char - 'A') + 10u); + } + } + + if (parse_dig < nbr_base) { /* If parse char valid for nbr base ... */ + if (ovf == DEF_NO) { /* ... & nbr NOT yet ovf'd, ... */ + if (nbr <= Str_MultOvfThTbl_Int32U[nbr_base]) { + /* ... merge parse char dig into nbr. */ + nbr *= nbr_base; + nbr += parse_dig; + if (nbr < parse_dig) { + ovf = DEF_YES; + } + } else { + ovf = DEF_YES; + } + } + pstr_parse++; + + } else { /* Invalid char parsed (see Note #2a1C1a). */ + done = DEF_YES; + } + + } else { /* Invalid OR NULL char parsed (see Note #2a1C1). */ + done = DEF_YES; + } + } + + if (ovf == DEF_YES) { /* If nbr ovf'd, ... */ + nbr = DEF_INT_32U_MAX_VAL; /* ... rtn max int val (see Note #2a3A1). */ + } + + + if (pstr_parse != pstr_parse_nbr) { /* If final parse str != init'l parse nbr str, .. */ + *pstr_next = (CPU_CHAR *)pstr_parse; /* .. rtn parse str's next char (see Note #2a2B2); .. */ + } else { + *pstr_next = (CPU_CHAR *)pstr; /* .. else rtn initial parse str (see Note #2a2A2). */ + } + + *pnbr_neg = neg; /* Rtn neg nbr status. */ + + + return (nbr); +} + diff --git a/rtos/uC-LIB/lib_str.h b/rtos/uC-LIB/lib_str.h new file mode 100644 index 00000000..24dddaac --- /dev/null +++ b/rtos/uC-LIB/lib_str.h @@ -0,0 +1,418 @@ +/* +********************************************************************************************************* +* uC/LIB +* Custom Library Modules +* +* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ASCII STRING MANAGEMENT +* +* Filename : lib_str.h +* Version : V1.39.00 +********************************************************************************************************* +* Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software. +* +* (a) ALL standard library functions are implemented in the custom library modules : +* +* (1) \\lib_*.* +* +* (2) \\Ports\\\lib*_a.* +* +* where +* directory path for custom library software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (b) Product-specific library functions are implemented in individual products. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MODULE +* +* Note(s) : (1) This string library header file is protected from multiple pre-processor inclusion through +* use of the string library module present pre-processor macro definition. +********************************************************************************************************* +*/ + +#ifndef LIB_STR_MODULE_PRESENT /* See Note #1. */ +#define LIB_STR_MODULE_PRESENT + + +/* +********************************************************************************************************* +* ASCII STRING CONFIGURATION DEFINES +* +* Note(s) : (1) Some ASCII string configuration #define's MUST be available PRIOR to including any +* application configuration (see 'INCLUDE FILES Note #1a'). +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STRING FLOATING POINT DEFINES +* +* Note(s) : (1) (a) (1) The maximum accuracy for 32-bit floating-point numbers : +* +* +* Maximum Accuracy log [Internal-Base ^ (Number-Internal-Base-Digits)] +* 32-bit Floating-point Number = ----------------------------------------------------- +* log [External-Base] +* +* log [2 ^ 24] +* = -------------- +* log [10] +* +* < 7.225 Base-10 Digits +* +* where +* Internal-Base Internal number base of floating- +* point numbers (i.e. 2) +* External-Base External number base of floating- +* point numbers (i.e. 10) +* Number-Internal-Base-Digits Number of internal number base +* significant digits (i.e. 24) +* +* (2) Also, since some 32-bit floating-point calculations are converted to 32-bit +* unsigned numbers, the maximum accuracy is limited to the maximum accuracy +* for 32-bit unsigned numbers of 9 digits. +* +* (b) Some CPUs' &/or compilers' floating-point implementations MAY further reduce the +* maximum accuracy. +********************************************************************************************************* +*/ + +#define LIB_STR_FP_MAX_NBR_DIG_SIG_MIN 1u +#define LIB_STR_FP_MAX_NBR_DIG_SIG_MAX 9u /* See Note #1a2. */ +#define LIB_STR_FP_MAX_NBR_DIG_SIG_DFLT 7u /* See Note #1a1. */ + + +/* +********************************************************************************************************* +* INCLUDE FILES +* +* Note(s) : (1) The custom library software files are located in the following directories : +* +* (a) \\lib_cfg.h +* +* (b) \\lib_*.* +* +* where +* directory path for Your Product's Application +* directory path for custom library software +* +* (2) CPU-configuration software files are located in the following directories : +* +* (a) \\cpu_*.* +* (b) \\\\cpu*.* +* +* where +* directory path for common CPU-compiler software +* directory name for specific processor (CPU) +* directory name for specific compiler +* +* (3) Compiler MUST be configured to include as additional include path directories : +* +* (a) '\\' directory See Note #1a +* +* (b) '\\' directory See Note #1b +* +* (c) (1) '\\' directory See Note #2a +* (2) '\\\\' directory See Note #2b +* +* (4) NO compiler-supplied standard library functions SHOULD be used. +* +* #### The reference to standard library header files SHOULD be removed once all custom +* library functions are implemented WITHOUT reference to ANY standard library function(s). +* +* See also 'STANDARD LIBRARY MACRO'S Note #1'. +********************************************************************************************************* +*/ + +#include + +#include +#include + +#include + +#if 0 /* See Note #4. */ +#include +#endif + + +/* +********************************************************************************************************* +* EXTERNS +********************************************************************************************************* +*/ + +#ifdef LIB_STR_MODULE +#define LIB_STR_EXT +#else +#define LIB_STR_EXT extern +#endif + + +/* +********************************************************************************************************* +* DEFAULT CONFIGURATION +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STRING FLOATING POINT CONFIGURATION +* +* Note(s) : (1) Configure LIB_STR_CFG_FP_EN to enable/disable floating point string function(s). +* +* (2) Configure LIB_STR_CFG_FP_MAX_NBR_DIG_SIG to configure the maximum number of significant +* digits to calculate &/or display for floating point string function(s). +* +* See also 'STRING FLOATING POINT DEFINES Note #1'. +********************************************************************************************************* +*/ + + /* Configure floating point feature(s) [see Note #1] : */ +#ifndef LIB_STR_CFG_FP_EN +#define LIB_STR_CFG_FP_EN DEF_DISABLED + /* DEF_DISABLED Floating point functions DISABLED */ + /* DEF_ENABLED Floating point functions ENABLED */ +#endif + + /* Configure floating point feature(s)' number of ... */ + /* ... significant digits (see Note #2). */ +#ifndef LIB_STR_CFG_FP_MAX_NBR_DIG_SIG +#define LIB_STR_CFG_FP_MAX_NBR_DIG_SIG LIB_STR_FP_MAX_NBR_DIG_SIG_DFLT +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +#define STR_CR_LF "\r\n" +#define STR_LF_CR "\n\r" +#define STR_NEW_LINE STR_CR_LF +#define STR_PARENT_PATH ".." + +#define STR_CR_LF_LEN (sizeof(STR_CR_LF) - 1) +#define STR_LF_CR_LEN (sizeof(STR_LF_CR) - 1) +#define STR_NEW_LINE_LEN (sizeof(STR_NEW_LINE) - 1) +#define STR_PARENT_PATH_LEN (sizeof(STR_PARENT_PATH) - 1) + + +/* +********************************************************************************************************* +* DATA TYPES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MACRO'S +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STANDARD LIBRARY MACRO'S +* +* Note(s) : (1) NO compiler-supplied standard library functions SHOULD be used. +* +* #### The reference to standard memory functions SHOULD be removed once all custom library +* functions are implemented WITHOUT reference to ANY standard library function(s). +* +* See also 'INCLUDE FILES Note #3'. +********************************************************************************************************* +*/ + + /* See Note #1. */ +#define Str_FmtPrint snprintf +#define Str_FmtScan sscanf + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + /* ------------------ STR LEN FNCTS ------------------ */ +CPU_SIZE_T Str_Len (const CPU_CHAR *pstr); + +CPU_SIZE_T Str_Len_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max); + + + /* ------------------ STR COPY FNCTS ------------------ */ +CPU_CHAR *Str_Copy ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src); + +CPU_CHAR *Str_Copy_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_src, + CPU_SIZE_T len_max); + + +CPU_CHAR *Str_Cat ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat); + +CPU_CHAR *Str_Cat_N ( CPU_CHAR *pstr_dest, + const CPU_CHAR *pstr_cat, + CPU_SIZE_T len_max); + + + /* ------------------ STR CMP FNCTS ------------------ */ +CPU_INT16S Str_Cmp (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str); + +CPU_INT16S Str_Cmp_N (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max); + +CPU_INT16S Str_CmpIgnoreCase (const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str); + +CPU_INT16S Str_CmpIgnoreCase_N(const CPU_CHAR *p1_str, + const CPU_CHAR *p2_str, + CPU_SIZE_T len_max); + + + /* ------------------ STR SRCH FNCTS ------------------ */ +CPU_CHAR *Str_Char (const CPU_CHAR *pstr, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Last (const CPU_CHAR *pstr, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Last_N (const CPU_CHAR *pstr, + CPU_SIZE_T len_max, + CPU_CHAR srch_char); + +CPU_CHAR *Str_Char_Replace ( CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace); + +CPU_CHAR *Str_Char_Replace_N ( CPU_CHAR *pstr, + CPU_CHAR char_srch, + CPU_CHAR char_replace, + CPU_SIZE_T len_max); + +CPU_CHAR *Str_Str (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch); + +CPU_CHAR *Str_Str_N (const CPU_CHAR *pstr, + const CPU_CHAR *pstr_srch, + CPU_SIZE_T len_max); + + + /* ------------------ STR FMT FNCTS ------------------ */ +CPU_CHAR *Str_FmtNbr_Int32U ( CPU_INT32U nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +CPU_CHAR *Str_FmtNbr_Int32S ( CPU_INT32S nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_base, + CPU_CHAR lead_char, + CPU_BOOLEAN lower_case, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); + +#if (LIB_STR_CFG_FP_EN == DEF_ENABLED) +CPU_CHAR *Str_FmtNbr_32 ( CPU_FP32 nbr, + CPU_INT08U nbr_dig, + CPU_INT08U nbr_dp, + CPU_CHAR lead_char, + CPU_BOOLEAN nul, + CPU_CHAR *pstr); +#endif + + + /* ----------------- STR PARSE FNCTS ------------------ */ +CPU_INT32U Str_ParseNbr_Int32U(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base); + +CPU_INT32S Str_ParseNbr_Int32S(const CPU_CHAR *pstr, + CPU_CHAR **pstr_next, + CPU_INT08U nbr_base); + + +/* +********************************************************************************************************* +* CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#ifndef LIB_STR_CFG_FP_EN +#error "LIB_STR_CFG_FP_EN not #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + +#elif ((LIB_STR_CFG_FP_EN != DEF_DISABLED) && \ + (LIB_STR_CFG_FP_EN != DEF_ENABLED )) +#error "LIB_STR_CFG_FP_EN illegally #define'd in 'lib_cfg.h'" +#error " [MUST be DEF_DISABLED] " +#error " [ || DEF_ENABLED ] " + + +#elif (LIB_STR_CFG_FP_EN == DEF_ENABLED) + +#ifndef LIB_STR_CFG_FP_MAX_NBR_DIG_SIG +#error "LIB_STR_CFG_FP_MAX_NBR_DIG_SIG not #define'd in 'lib_cfg.h' " +#error " [MUST be >= LIB_STR_FP_MAX_NBR_DIG_SIG_MIN]" +#error " [ && <= LIB_STR_FP_MAX_NBR_DIG_SIG_MAX]" + +#elif (DEF_CHK_VAL(LIB_STR_CFG_FP_MAX_NBR_DIG_SIG, \ + LIB_STR_FP_MAX_NBR_DIG_SIG_MIN, \ + LIB_STR_FP_MAX_NBR_DIG_SIG_MAX) != DEF_OK) +#error "LIB_STR_CFG_FP_MAX_NBR_DIG_SIG illegally #define'd in 'lib_cfg.h' " +#error " [MUST be >= LIB_STR_FP_MAX_NBR_DIG_SIG_MIN]" +#error " [ && <= LIB_STR_FP_MAX_NBR_DIG_SIG_MAX]" +#endif + +#endif + + +/* +********************************************************************************************************* +* MODULE END +* +* Note(s) : (1) See 'lib_str.h MODULE'. +********************************************************************************************************* +*/ + +#endif /* End of lib str module include. */ + diff --git a/rtos/uC-LIB/readme.md b/rtos/uC-LIB/readme.md new file mode 100644 index 00000000..3aecd494 --- /dev/null +++ b/rtos/uC-LIB/readme.md @@ -0,0 +1,5 @@ +# uC/LIB + +Designed with Micrium’s renowned quality, scalability and reliability, the purpose of µC/LIB is to provide a clean, organized ANSI C implementation of the most common standard library functions, macros, and constants. + +## For the complete documentation, visit https://doc.micrium.com/display/ucos/ \ No newline at end of file diff --git a/rtos/uC-OS3/Cfg/app_cfg.h b/rtos/uC-OS3/Cfg/app_cfg.h new file mode 100644 index 00000000..88cb1625 --- /dev/null +++ b/rtos/uC-OS3/Cfg/app_cfg.h @@ -0,0 +1,105 @@ +/* +********************************************************************************************************* +* EXAMPLE CODE +* +* (c) Copyright 2009-2013; Micrium, Inc.; Weston, FL +* +* All rights reserved. Protected by international copyright laws. +* +* Please feel free to use any application code labeled as 'EXAMPLE CODE' in +* your application products. Example code may be used as is, in whole or in +* part, or may be used as a reference only. +* +* Please help us continue to provide the Embedded community with the finest +* software available. Your honesty is greatly appreciated. +* +* You can contact us at www.micrium.com. +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* APPLICATION CONFIGURATION +* +* uC/OS-III on POSIX +* +* Filename : app.c +* Version : V1.00 +* Programmer(s) : EJ +* +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* MODULE +********************************************************************************************************* +*/ + +#ifndef APP_CFG_MODULE_PRESENT +#define APP_CFG_MODULE_PRESENT + + +/* +********************************************************************************************************* +* INCLUDE +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* TASK PRIORITIES +********************************************************************************************************* +*/ + +#define APP_CFG_TASK_START_PRIO 33 + +#define OS_TASK_TMR_PRIO (OS_LOWEST_PRIO - 2) + + +/* +********************************************************************************************************* +* TASK STACK SIZES +* Size of the task stacks (# of OS_STK entries) +********************************************************************************************************* +*/ + +#define APP_CFG_TASK_START_STK_SIZE 4096 + + +/* +********************************************************************************************************* +* uC/TCP-IP v2.10 +********************************************************************************************************* +*/ + + +/* +********************************************************************************************************* +* TRACE / DEBUG CONFIGURATION +********************************************************************************************************* +*/ +#ifndef TRACE_LEVEL_OFF +#define TRACE_LEVEL_OFF 0 +#endif + +#ifndef TRACE_LEVEL_INFO +#define TRACE_LEVEL_INFO 1 +#endif + +#ifndef TRACE_LEVEL_DEBUG +#define TRACE_LEVEL_DEBUG 2 +#endif + +#define APP_TRACE_LEVEL TRACE_LEVEL_OFF +#define APP_TRACE printf + +#define APP_TRACE_INFO(x) ((APP_TRACE_LEVEL >= TRACE_LEVEL_INFO) ? (void)(APP_TRACE x) : (void)0) +#define APP_TRACE_DBG(x) ((APP_TRACE_LEVEL >= TRACE_LEVEL_DEBUG) ? (void)(APP_TRACE x) : (void)0) + +#define APP_TRACE_DEBUG(x) APP_TRACE_DBG(x) + +#endif diff --git a/rtos/uC-OS3/Cfg/os_app_hooks.c b/rtos/uC-OS3/Cfg/os_app_hooks.c new file mode 100644 index 00000000..5beff5c9 --- /dev/null +++ b/rtos/uC-OS3/Cfg/os_app_hooks.c @@ -0,0 +1,262 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* APPLICATION HOOKS +* +* Filename : os_app_hooks.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include +#include "os_app_hooks.h" + + +/* +************************************************************************************************************************ +* SET ALL APPLICATION HOOKS +* +* Description: Set ALL application hooks. +* +* Arguments : none. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_SetAllHooks (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + OS_AppIdleTaskHookPtr = App_OS_IdleTaskHook; + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + OS_AppRedzoneHitHookPtr = App_OS_RedzoneHitHook; +#endif + + OS_AppStatTaskHookPtr = App_OS_StatTaskHook; + + OS_AppTaskCreateHookPtr = App_OS_TaskCreateHook; + + OS_AppTaskDelHookPtr = App_OS_TaskDelHook; + + OS_AppTaskReturnHookPtr = App_OS_TaskReturnHook; + + OS_AppTaskSwHookPtr = App_OS_TaskSwHook; + + OS_AppTimeTickHookPtr = App_OS_TimeTickHook; + CPU_CRITICAL_EXIT(); +#endif +} + + +/* +************************************************************************************************************************ +* CLEAR ALL APPLICATION HOOKS +* +* Description: Clear ALL application hooks. +* +* Arguments : none. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_ClrAllHooks (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + OS_AppIdleTaskHookPtr = (OS_APP_HOOK_VOID)0; + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + OS_AppRedzoneHitHookPtr = (OS_APP_HOOK_TCB)0; +#endif + + OS_AppStatTaskHookPtr = (OS_APP_HOOK_VOID)0; + + OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB)0; + + OS_AppTaskDelHookPtr = (OS_APP_HOOK_TCB)0; + + OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB)0; + + OS_AppTaskSwHookPtr = (OS_APP_HOOK_VOID)0; + + OS_AppTimeTickHookPtr = (OS_APP_HOOK_VOID)0; + CPU_CRITICAL_EXIT(); +#endif +} + +/* +************************************************************************************************************************ +* APPLICATION IDLE TASK HOOK +* +* Description: This function is called by the idle task. This hook has been added to allow you to do such things as +* STOP the CPU to conserve power. +* +* Arguments : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_IdleTaskHook (void) +{ + +} + +/* +************************************************************************************************************************ +* APPLICATION REDZONE HIT HOOK +* +* Description: This function is called when a task's stack overflowed. +* +* Arguments : p_tcb is a pointer to the task control block of the offending task. NULL if ISR. +* +* Note(s) : None. +************************************************************************************************************************ +*/ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void App_OS_RedzoneHitHook (OS_TCB *p_tcb) +{ + (void)&p_tcb; + CPU_SW_EXCEPTION(;); +} +#endif + + +/* +************************************************************************************************************************ +* APPLICATION STATISTIC TASK HOOK +* +* Description: This function is called every second by uC/OS-III's statistics task. This allows your application to add +* functionality to the statistics task. +* +* Arguments : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_StatTaskHook (void) +{ + +} + + +/* +************************************************************************************************************************ +* APPLICATION TASK CREATION HOOK +* +* Description: This function is called when a task is created. +* +* Arguments : p_tcb is a pointer to the task control block of the task being created. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_TaskCreateHook (OS_TCB *p_tcb) +{ + (void)p_tcb; +} + + +/* +************************************************************************************************************************ +* APPLICATION TASK DELETION HOOK +* +* Description: This function is called when a task is deleted. +* +* Arguments : p_tcb is a pointer to the task control block of the task being deleted. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_TaskDelHook (OS_TCB *p_tcb) +{ + (void)p_tcb; +} + + +/* +************************************************************************************************************************ +* APPLICATION TASK RETURN HOOK +* +* Description: This function is called if a task accidentally returns. In other words, a task should either be an +* infinite loop or delete itself when done. +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task that is returning. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void App_OS_TaskReturnHook (OS_TCB *p_tcb) +{ + (void)p_tcb; +} + + +/* +************************************************************************************************************************ +* APPLICATION TASK SWITCH HOOK +* +* Description: This function is called when a task switch is performed. This allows you to perform other operations +* during a context switch. +* +* Arguments : none +* +* Note(s) : 1) Interrupts are disabled during this call. +* 2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task that will be +* 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points to the task being switched out +* (i.e. the preempted task). +************************************************************************************************************************ +*/ + +void App_OS_TaskSwHook (void) +{ + +} + + +/* +************************************************************************************************************************ +* APPLICATION TICK HOOK +* +* Description: This function is called every tick. +* +* Arguments : none +* +* Note(s) : 1) This function is assumed to be called from the Tick ISR. +************************************************************************************************************************ +*/ + +void App_OS_TimeTickHook (void) +{ + +} diff --git a/rtos/uC-OS3/Cfg/os_app_hooks.h b/rtos/uC-OS3/Cfg/os_app_hooks.h new file mode 100644 index 00000000..5558bcc5 --- /dev/null +++ b/rtos/uC-OS3/Cfg/os_app_hooks.h @@ -0,0 +1,74 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* APPLICATION HOOKS +* +* Filename : os_app_hooks.h +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#ifndef OS_APP_HOOKS_H +#define OS_APP_HOOKS_H + + +#ifdef OS_APP_HOOKS_H_GLOBALS +#define OS_APP_HOOKS_H_EXT +#else +#define OS_APP_HOOKS_H_EXT extern +#endif + +/* +************************************************************************************************************************ +* INCLUDE HEADER FILES +************************************************************************************************************************ +*/ + +#include + +/* +************************************************************************************************************************ +* FUNCTION PROTOTYPES +************************************************************************************************************************ +*/ + +void App_OS_SetAllHooks (void); +void App_OS_ClrAllHooks (void); + + + /* ---------------------- HOOKS --------------------- */ +void App_OS_IdleTaskHook (void); + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void App_OS_RedzoneHitHook(OS_TCB *p_tcb); +#endif + +void App_OS_StatTaskHook (void); + +void App_OS_TaskCreateHook(OS_TCB *p_tcb); + +void App_OS_TaskDelHook (OS_TCB *p_tcb); + +void App_OS_TaskReturnHook(OS_TCB *p_tcb); + +void App_OS_TaskSwHook (void); + +void App_OS_TimeTickHook (void); + +#endif diff --git a/rtos/uC-OS3/Cfg/os_cfg.h b/rtos/uC-OS3/Cfg/os_cfg.h new file mode 100644 index 00000000..49240667 --- /dev/null +++ b/rtos/uC-OS3/Cfg/os_cfg.h @@ -0,0 +1,118 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* CONFIGURATION FILE +* +* Filename : os_cfg.h +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#ifndef OS_CFG_H +#define OS_CFG_H + + /* --------------------------- MISCELLANEOUS --------------------------- */ +#define OS_CFG_APP_HOOKS_EN 1u /* Enable (1) or Disable (0) application specific hooks */ +#define OS_CFG_ARG_CHK_EN 1u /* Enable (1) or Disable (0) argument checking */ +#define OS_CFG_CALLED_FROM_ISR_CHK_EN 1u /* Enable (1) or Disable (0) check for called from ISR */ +#define OS_CFG_DBG_EN 1u /* Enable (1) or Disable (0) debug code/variables */ +#define OS_CFG_TICK_EN 1u /* Enable (1) or Disable (0) the kernel tick */ +#define OS_CFG_DYN_TICK_EN 0u /* Enable (1) or Disable (0) the Dynamic Tick */ +#define OS_CFG_INVALID_OS_CALLS_CHK_EN 1u /* Enable (1) or Disable (0) checks for invalid kernel calls */ +#define OS_CFG_OBJ_TYPE_CHK_EN 1u /* Enable (1) or Disable (0) object type checking */ +#define OS_CFG_TS_EN 0u /* Enable (1) or Disable (0) time stamping */ + +#define OS_CFG_PRIO_MAX 64u /* Defines the maximum number of task priorities (see OS_PRIO data type) */ + +#define OS_CFG_SCHED_LOCK_TIME_MEAS_EN 0u /* Include code to measure scheduler lock time */ +#define OS_CFG_SCHED_ROUND_ROBIN_EN 1u /* Include code for Round-Robin scheduling */ + +#define OS_CFG_STK_SIZE_MIN 64u /* Minimum allowable task stack size */ + + + /* --------------------------- EVENT FLAGS ----------------------------- */ +#define OS_CFG_FLAG_EN 1u /* Enable (1) or Disable (0) code generation for EVENT FLAGS */ +#define OS_CFG_FLAG_DEL_EN 1u /* Include code for OSFlagDel() */ +#define OS_CFG_FLAG_MODE_CLR_EN 1u /* Include code for Wait on Clear EVENT FLAGS */ +#define OS_CFG_FLAG_PEND_ABORT_EN 1u /* Include code for OSFlagPendAbort() */ + + + /* ------------------------ MEMORY MANAGEMENT ------------------------- */ +#define OS_CFG_MEM_EN 1u /* Enable (1) or Disable (0) code generation for the MEMORY MANAGER */ + + + /* ------------------- MUTUAL EXCLUSION SEMAPHORES -------------------- */ +#define OS_CFG_MUTEX_EN 1u /* Enable (1) or Disable (0) code generation for MUTEX */ +#define OS_CFG_MUTEX_DEL_EN 1u /* Include code for OSMutexDel() */ +#define OS_CFG_MUTEX_PEND_ABORT_EN 1u /* Include code for OSMutexPendAbort() */ + + + /* -------------------------- MESSAGE QUEUES -------------------------- */ +#define OS_CFG_Q_EN 1u /* Enable (1) or Disable (0) code generation for QUEUES */ +#define OS_CFG_Q_DEL_EN 1u /* Include code for OSQDel() */ +#define OS_CFG_Q_FLUSH_EN 1u /* Include code for OSQFlush() */ +#define OS_CFG_Q_PEND_ABORT_EN 1u /* Include code for OSQPendAbort() */ + + + /* ---------------------------- SEMAPHORES ----------------------------- */ +#define OS_CFG_SEM_EN 1u /* Enable (1) or Disable (0) code generation for SEMAPHORES */ +#define OS_CFG_SEM_DEL_EN 1u /* Include code for OSSemDel() */ +#define OS_CFG_SEM_PEND_ABORT_EN 1u /* Include code for OSSemPendAbort() */ +#define OS_CFG_SEM_SET_EN 1u /* Include code for OSSemSet() */ + + + /* -------------------------- TASK MANAGEMENT -------------------------- */ +#define OS_CFG_STAT_TASK_EN 1u /* Enable (1) or Disable (0) the statistics task */ +#define OS_CFG_STAT_TASK_STK_CHK_EN 1u /* Check task stacks from the statistic task */ + +#define OS_CFG_TASK_CHANGE_PRIO_EN 1u /* Include code for OSTaskChangePrio() */ +#define OS_CFG_TASK_DEL_EN 1u /* Include code for OSTaskDel() */ +#define OS_CFG_TASK_IDLE_EN 1u /* Include the idle task */ +#define OS_CFG_TASK_PROFILE_EN 1u /* Include variables in OS_TCB for profiling */ +#define OS_CFG_TASK_Q_EN 1u /* Include code for OSTaskQXXXX() */ +#define OS_CFG_TASK_Q_PEND_ABORT_EN 1u /* Include code for OSTaskQPendAbort() */ +#define OS_CFG_TASK_REG_TBL_SIZE 1u /* Number of task specific registers */ + +#define OS_CFG_TASK_STK_REDZONE_EN 0u /* Enable (1) or Disable (0) stack redzone */ +#define OS_CFG_TASK_STK_REDZONE_DEPTH 8u /* Depth of the stack redzone */ + +#define OS_CFG_TASK_SEM_PEND_ABORT_EN 1u /* Include code for OSTaskSemPendAbort() */ +#define OS_CFG_TASK_SUSPEND_EN 1u /* Include code for OSTaskSuspend() and OSTaskResume() */ + + + /* ------------------ TASK LOCAL STORAGE MANAGEMENT ------------------- */ +#define OS_CFG_TLS_TBL_SIZE 0u /* Include code for Task Local Storage (TLS) registers */ + + + /* ------------------------- TIME MANAGEMENT -------------------------- */ +#define OS_CFG_TIME_DLY_HMSM_EN 1u /* Include code for OSTimeDlyHMSM() */ +#define OS_CFG_TIME_DLY_RESUME_EN 1u /* Include code for OSTimeDlyResume() */ + + + /* ------------------------- TIMER MANAGEMENT -------------------------- */ +#define OS_CFG_TMR_EN 1u /* Enable (1) or Disable (0) code generation for TIMERS */ +#define OS_CFG_TMR_DEL_EN 1u /* Enable (1) or Disable (0) code generation for OSTmrDel() */ + + + /* ------------------------- TRACE RECORDER ---------------------------- */ +#define OS_CFG_TRACE_EN 0u /* Enable (1) or Disable (0) uC/OS-III Trace instrumentation */ +#define OS_CFG_TRACE_API_ENTER_EN 0u /* Enable (1) or Disable (0) uC/OS-III Trace API enter instrumentation */ +#define OS_CFG_TRACE_API_EXIT_EN 0u /* Enable (1) or Disable (0) uC/OS-III Trace API exit instrumentation */ + +#endif diff --git a/rtos/uC-OS3/Cfg/os_cfg_app.h b/rtos/uC-OS3/Cfg/os_cfg_app.h new file mode 100644 index 00000000..09d8c509 --- /dev/null +++ b/rtos/uC-OS3/Cfg/os_cfg_app.h @@ -0,0 +1,80 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* OS CONFIGURATION (APPLICATION SPECIFICS) +* +* Filename : os_cfg_app.h +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#ifndef OS_CFG_APP_H +#define OS_CFG_APP_H + +/* +************************************************************************************************************************** +* CONSTANTS +************************************************************************************************************************** +*/ + /* ------------------ MISCELLANEOUS ------------------- */ + /* Stack size of ISR stack (number of CPU_STK elements) */ +#define OS_CFG_ISR_STK_SIZE 128u + /* Maximum number of messages */ +#define OS_CFG_MSG_POOL_SIZE 32u + /* Stack limit position in percentage to empty */ +#define OS_CFG_TASK_STK_LIMIT_PCT_EMPTY 10u + + + /* -------------------- IDLE TASK --------------------- */ + /* Stack size (number of CPU_STK elements) */ +#define OS_CFG_IDLE_TASK_STK_SIZE 64u + + + /* ------------------ STATISTIC TASK ------------------ */ + /* Priority */ +#define OS_CFG_STAT_TASK_PRIO ((OS_PRIO)(OS_CFG_PRIO_MAX-2u)) + /* Rate of execution (1 to 10 Hz) */ +#define OS_CFG_STAT_TASK_RATE_HZ 10u + /* Stack size (number of CPU_STK elements) */ +#define OS_CFG_STAT_TASK_STK_SIZE 100u + + + /* ---------------------- TICKS ----------------------- */ + /* Tick rate in Hertz (10 to 1000 Hz) */ +#define OS_CFG_TICK_RATE_HZ 1000u + + + /* --------------------- TIMERS ----------------------- */ + /* Priority of 'Timer Task' */ +#define OS_CFG_TMR_TASK_PRIO ((OS_PRIO)(OS_CFG_PRIO_MAX-3u)) + /* Stack size (number of CPU_STK elements) */ +#define OS_CFG_TMR_TASK_STK_SIZE 128u + + /* DEPRECATED - Rate for timers (10 Hz Typ.) */ + /* The timer task now calculates its timeouts based */ + /* on the timers in the list. It no longer runs at a */ + /* static frequency. */ + /* This define is included for compatibility reasons. */ + /* It will determine the period of a timer tick. */ + /* We recommend setting it to OS_CFG_TICK_RATE_HZ */ + /* for new projects. */ +#define OS_CFG_TMR_TASK_RATE_HZ 10u + + +#endif diff --git a/rtos/uC-OS3/LICENSE b/rtos/uC-OS3/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/rtos/uC-OS3/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/rtos/uC-OS3/NOTICE b/rtos/uC-OS3/NOTICE new file mode 100644 index 00000000..e8cacd2c --- /dev/null +++ b/rtos/uC-OS3/NOTICE @@ -0,0 +1,28 @@ +ATTENTION ALL USERS OF THIS REPOSITORY: + +The original work found in this repository is provided by Silicon Labs under the +Apache License, Version 2.0. + +Any third party may contribute derivative works to the original work in which +modifications are clearly identified as being licensed under: + + (1) the Apache License, Version 2.0 or a compatible open source license; or + (2) under a proprietary license with a copy of such license deposited. + +All posted derivative works must clearly identify which license choice has been +elected. + +No such posted derivative works will be considered to be a “Contribution” under +the Apache License, Version 2.0. + +SILICON LABS MAKES NO WARRANTY WITH RESPECT TO ALL POSTED THIRD PARTY CONTENT +AND DISCLAIMS ALL OTHER WARRANTIES OR LIABILITIES, INCLUDING ALL WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OWNERSHIP, +NON-INFRINGEMENT, AND NON-MISAPPROPRIATION. + +In the event a derivative work is desired to be submitted to Silicon Labs as a +“Contribution” under the Apache License, Version 2.0, a “Contributor” must give +written email notice to micrium@weston-embedded.com. Unless an email response in +the affirmative to accept the derivative work as a “Contribution”, such email +submission should be considered to have not been incorporated into the original +work. diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu.h b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu.h new file mode 100644 index 00000000..d6b26c87 --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu.h @@ -0,0 +1,177 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ARMv6-M Port +* +* File : os_cpu.h +* Version : V3.08.00 +********************************************************************************************************* +* For : ARMv6-M Cortex-M0 or Cortex-M0+ +* Mode : Thumb2 +* Toolchain : GNU C Compiler +********************************************************************************************************* +* Note(s) : (1) This port supports the ARM Cortex-M0 and Cortex-M0+ architectures. +********************************************************************************************************* +*/ + +#ifndef OS_CPU_H +#define OS_CPU_H + +#ifdef OS_CPU_GLOBALS +#define OS_CPU_EXT +#else +#define OS_CPU_EXT extern +#endif + + +/* +********************************************************************************************************* +* EXTERNAL C LANGUAGE LINKAGE +* +* Note(s) : (1) C++ compilers MUST 'extern'ally declare ALL C function prototypes & variable/object +* declarations for correct C language linkage. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +extern "C" { /* See Note #1. */ +#endif + + +/* +********************************************************************************************************* +* DEFINES +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MACROS +********************************************************************************************************* +*/ + +#define OS_TASK_SW() OSCtxSw() + +#define OS_TASK_SW_SYNC() __asm__ __volatile__ ("isb" : : : "memory") + + +/* +********************************************************************************************************* +* TIMESTAMP CONFIGURATION +* +* Note(s) : (1) OS_TS_GET() is generally defined as CPU_TS_Get32() to allow CPU timestamp timer to be of +* any data type size. +* +* (2) For architectures that provide 32-bit or higher precision free running counters +* (i.e. cycle count registers): +* +* (a) OS_TS_GET() may be defined as CPU_TS_TmrRd() to improve performance when retrieving +* the timestamp. +* +* (b) CPU_TS_TmrRd() MUST be configured to be greater or equal to 32-bits to avoid +* truncation of TS. +********************************************************************************************************* +*/ + +#if OS_CFG_TS_EN == 1u +#define OS_TS_GET() (CPU_TS)CPU_TS_TmrRd() /* See Note #2a. */ +#else +#define OS_TS_GET() (CPU_TS)0u +#endif + +#if (CPU_CFG_TS_32_EN > 0u) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32) + /* CPU_CFG_TS_TMR_SIZE MUST be >= 32-bit (see Note #2b). */ +#error "cpu_cfg.h, CPU_CFG_TS_TMR_SIZE MUST be >= CPU_WORD_SIZE_32" +#endif + + +/* +********************************************************************************************************* +* OS TICK INTERRUPT PRIORITY CONFIGURATION +* +* Note(s) : (1) For systems that don't need any high, real-time priority interrupts; the tick interrupt +* should be configured as the highest priority interrupt but won't adversely affect system +* operations. +* +* (2) For systems that need one or more high, real-time interrupts; these should be configured +* higher than the tick interrupt which MAY delay execution of the tick interrupt. +* +* (a) If the higher priority interrupts do NOT continually consume CPU cycles but only +* occasionally delay tick interrupts, then the real-time interrupts can successfully +* handle their intermittent/periodic events with the system not losing tick interrupts +* but only increasing the jitter. +* +* (b) If the higher priority interrupts consume enough CPU cycles to continually delay the +* tick interrupt, then the CPU/system is most likely over-burdened & can't be expected +* to handle all its interrupts/tasks. The system time reference gets compromised as a +* result of losing tick interrupts. +********************************************************************************************************* +*/ + +#ifndef OS_CPU_CFG_SYSTICK_PRIO +#define OS_CPU_CFG_SYSTICK_PRIO 0u +#endif + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +OS_CPU_EXT CPU_STK *OS_CPU_ExceptStkBase; + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +* +********************************************************************************************************* +*/ + + /* See OS_CPU_A.ASM */ +void OSCtxSw (void); +void OSIntCtxSw (void); +void OSStartHighRdy (void); + +void OS_CPU_PendSVHandler (void); + + +void OS_CPU_SysTickHandler(void); +void OS_CPU_SysTickInit (CPU_INT32U cnts); + +/* +********************************************************************************************************* +* EXTERNAL C LANGUAGE LINKAGE END +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} /* End of 'extern'al C lang linkage. */ +#endif + + +/* +********************************************************************************************************* +* MODULE END +********************************************************************************************************* +*/ + +#endif diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_a.s b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_a.s new file mode 100644 index 00000000..140eb72f --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_a.s @@ -0,0 +1,235 @@ +@******************************************************************************************************** +@ uC/OS-III +@ The Real-Time Kernel +@ +@ Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + +@******************************************************************************************************** +@ +@ ARMv6-M Port +@ +@ File : os_cpu_a.s +@ Version : V3.08.00 +@******************************************************************************************************** +@ For : ARMv6-M Cortex-M0 or Cortex-M0+ +@ Mode : Thumb2 +@ Toolchain : GNU C Compiler +@******************************************************************************************************** +@ Note(s) : (1) This port supports the ARM Cortex-M0 and Cortex-M0+ architectures. +@******************************************************************************************************** + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + + @ External references. + .extern OSPrioCur + .extern OSPrioHighRdy + .extern OSTCBCurPtr + .extern OSTCBHighRdyPtr + .extern OSIntExit + .extern OSTaskSwHook + .extern OS_CPU_ExceptStkBase + + + .global OSStartHighRdy @ Functions declared in this file + .global OSCtxSw + .global OSIntCtxSw +.global OS_CPU_PendSVHandler + +@******************************************************************************************************** +@ EQUATES +@******************************************************************************************************** + +.equ NVIC_INT_CTRL, 0xE000ED04 @ Interrupt control state register. +.equ NVIC_SYSPRI14, 0xE000ED20 @ System priority register (priority 14). +.equ NVIC_PENDSV_PRI, 0x00FF0000 @ PendSV priority value (lowest). +.equ NVIC_PENDSVSET, 0x10000000 @ Value to trigger PendSV exception. + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + + .text + .align 2 + .thumb + .syntax unified + + +@******************************************************************************************************** +@ START MULTITASKING +@ void OSStartHighRdy(void) +@ +@ Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause +@ the first task to start. +@ +@ 2) OSStartHighRdy() MUST: +@ a) Setup PendSV exception priority to lowest; +@ b) Set initial PSP to 0, to tell context switcher this is first run; +@ c) Set the main stack to OS_CPU_ExceptStkBase +@ d) Trigger PendSV exception; +@ e) Enable interrupts (tasks will run with interrupts enabled). +@******************************************************************************************************** + +.thumb_func +OSStartHighRdy: + CPSID I @ Prevent interruption during context switch + LDR R0, =NVIC_SYSPRI14 @ Set the PendSV exception priority + LDR R1, =NVIC_PENDSV_PRI + STR R1, [R0] + + MOVS R0, #0 @ Set the PSP to 0 for initial context switch call + MSR PSP, R0 + BL OSTaskSwHook + + LDR R0, =OS_CPU_ExceptStkBase @ Initialize the MSP to the OS_CPU_ExceptStkBase + LDR R1, [R0] + MSR MSP, R1 + + LDR R0, =NVIC_INT_CTRL @ Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + + CPSIE I @ Enable interrupts at processor level + +OSStartHang: + B OSStartHang @ Should never get here + + +@******************************************************************************************************** +@ PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() +@ +@ Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function +@ triggers the PendSV exception which is where the real work is done. +@******************************************************************************************************** + +.thumb_func +OSCtxSw: + LDR R0, =NVIC_INT_CTRL @ Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + BX LR + + +@******************************************************************************************************** +@ PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw() +@ +@ Note(s) : 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as +@ the result of an interrupt. This function simply triggers a PendSV exception which will +@ be handled when there are no more interrupts active and interrupts are enabled. +@******************************************************************************************************** + +.thumb_func +OSIntCtxSw: + LDR R0, =NVIC_INT_CTRL @ Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + BX LR + + +@******************************************************************************************************** +@ HANDLE PendSV EXCEPTION +@ void OS_CPU_PendSVHandler(void) +@ +@ Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing +@ context switches with Cortex-M0. This is because the Cortex-M0 auto-saves half of the +@ processor context on any exception, and restores same on return from exception. So only +@ saving of R4-R11, LR is required and fixing up the stack pointers. Using the PendSV exception +@ this way means that context saving and restoring is identical whether it is initiated from +@ a thread or occurs due to an interrupt or exception. +@ +@ 2) Pseudo-code is: +@ a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch); +@ b) Adjust SP to make space for R4-R11 and LR register +@ c) Save the process SP in its TCB, OSTCBCurPtr->StkPtr = SP; +@ d) Save remaining regs R4-R11, LR on process stack; +@ e) Call OSTaskSwHook(); +@ f) Get current high priority, OSPrioCur = OSPrioHighRdy; +@ g) Get current ready thread TCB, OSTCBCurPtr = OSTCBHighRdyPtr; +@ h) Get new process SP from TCB, SP = OSTCBHighRdyPtr->StkPtr; +@ i) Adjust SP to the High Registers(R8-R11) & LR location +@ j) Restore R8-R11, and LR from new process stack; +@ k) Load PSP with new process SP +@ m) Restore remaining R4-R7 from new process stack +@ n) Perform exception return which will restore remaining context. +@ +@ 3) On entry into PendSV handler: +@ a) The following have been saved on the process stack (by processor): +@ xPSR, PC, LR, R12, R0-R3 +@ b) Processor mode is switched to Handler mode (from Thread mode) +@ c) Stack is Main stack (switched from Process stack) +@ d) OSTCBCurPtr points to the OS_TCB of the task to suspend +@ OSTCBHighRdyPtr points to the OS_TCB of the task to resume +@ +@ 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we +@ know that it will only be run when no other exception or interrupt is active, and +@ therefore safe to assume that context being switched out was using the process stack (PSP). +@******************************************************************************************************** + +.thumb_func +OS_CPU_PendSVHandler: + CPSID I @ Prevent interruption during context switch + MRS R0, PSP @ PSP is process stack pointer + + CMP R0, #0 + BEQ OS_CPU_PendSVHandler_nosave @ equivalent code to CBZ from M3 arch to M0 arch + @ Except that it does not change the condition code flags + + SUBS R0, R0, #0x24 @ Adjust SP to make space for Low, High & LR registers + LDR R1, =OSTCBCurPtr @ OSTCBCurPtr->StkPtr = SP; + LDR R1, [R1] + STR R0, [R1] @ R0 is SP of process being switched out + + STMIA R0!, {R4-R7} @ Store R4-R7(Low Registers) on process stack + MOV R4, R8 @ Move R8-R11 values to R4-R7 registers. + MOV R5, R9 + MOV R6, R10 + MOV R7, R11 + STMIA R0!, {R4-R7} @ Store R8-R11(High Registers) on process stack + MOV R3, R14 @ R3 is LR of process being switched out + STMIA R0!, {R3} @ Store LR (EXC_RETURN) on process stack. + + @ At this point, entire context of process has been saved +OS_CPU_PendSVHandler_nosave: + BL OSTaskSwHook @ OSTaskSwHook(); + + LDR R0, =OSPrioCur @ OSPrioCur = OSPrioHighRdy; + LDR R1, =OSPrioHighRdy + LDRB R2, [R1] + STRB R2, [R0] + + LDR R0, =OSTCBCurPtr @ OSTCBCurPtr = OSTCBHighRdyPtr; + LDR R1, =OSTCBHighRdyPtr + LDR R2, [R1] + STR R2, [R0] + + LDR R0, [R2] @ R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr; + + ADDS R0, #0x10 @ Adjust SP to High Registers(R8-R11) location + LDMFD R0!, {R4-R7} @ Load R8-R11 values from new process stack into R4-R7 + MOV R8, R4 @ Restore R8-R11 by moving their values from R4-R7 + MOV R9, R5 + MOV R10, R6 + MOV R11, R7 + + LDMFD R0!, {R3} @ R3 has the new process LR; R3 = LR (EXEC_RETURN) + MOV R14, R3 @ Restore LR (EXEC_RETURN) + + MSR PSP, R0 @ Load PSP with new process SP + + SUBS R0, #0x24 @ Adjust SP to Low registers(R4-R7) location + LDMFD R0!, {R4-R7} @ Restore remaining R4-R7 from new process stack + + CPSIE I + BX LR @ Exception return will restore remaining context + +.end diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_c.c b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_c.c new file mode 100644 index 00000000..29f733ab --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv6-M/os_cpu_c.c @@ -0,0 +1,511 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ARMv6-M Port +* +* File : os_cpu_c.c +* Version : V3.08.00 +********************************************************************************************************* +* For : ARMv6-M Cortex-M0 or Cortex-M0+ +* Mode : Thumb2 +********************************************************************************************************* +* Note(s) : (1) This port supports the ARM Cortex-M0 and Cortex-M0+ architectures. +********************************************************************************************************* +*/ + +#define OS_CPU_GLOBALS + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_cpu_c__c = "$Id: $"; +#endif + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include "../../../Source/os.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* IDLE TASK HOOK +* +* Description: This function is called by the idle task. This hook has been added to allow you to do +* such things as STOP the CPU to conserve power. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSIdleTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppIdleTaskHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* OS INITIALIZATION HOOK +* +* Description: This function is called by OSInit() at the beginning of OSInit(). +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSInitHook (void) +{ + /* 8-byte align the ISR stack. */ + OS_CPU_ExceptStkBase = (CPU_STK *)(OSCfg_ISRStkBasePtr + OSCfg_ISRStkSize); + OS_CPU_ExceptStkBase = (CPU_STK *)((CPU_STK)(OS_CPU_ExceptStkBase) & 0xFFFFFFF8); + +} + + +/* +********************************************************************************************************* +* REDZONE HIT HOOK +* +* Description: This function is called when a task's stack overflowed. +* +* Arguments : p_tcb Pointer to the task control block of the offending task. NULL if ISR. +* +* Note(s) : None. +********************************************************************************************************* +*/ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void OSRedzoneHitHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppRedzoneHitHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppRedzoneHitHookPtr)(p_tcb); + } else { + CPU_SW_EXCEPTION(;); + } +#else + (void)p_tcb; /* Prevent compiler warning */ + CPU_SW_EXCEPTION(;); +#endif +} +#endif + + +/* +********************************************************************************************************* +* STATISTIC TASK HOOK +* +* Description: This function is called every second by uC/OS-III's statistics task. This allows your +* application to add functionality to the statistics task. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSStatTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppStatTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppStatTaskHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* TASK CREATION HOOK +* +* Description: This function is called when a task is created. +* +* Arguments : p_tcb Pointer to the task control block of the task being created. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskCreateHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskCreateHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* TASK DELETION HOOK +* +* Description: This function is called when a task is deleted. +* +* Arguments : p_tcb Pointer to the task control block of the task being deleted. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskDelHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskDelHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskDelHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* TASK RETURN HOOK +* +* Description: This function is called if a task accidentally returns. In other words, a task should +* either be an infinite loop or delete itself when done. +* +* Arguments : p_tcb Pointer to the task control block of the task that is returning. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskReturnHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskReturnHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskReturnHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* INITIALIZE A TASK'S STACK +* +* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the +* stack frame of the task being created. This function is highly processor specific. +* +* Arguments : p_task Pointer to the task entry point address. +* +* p_arg Pointer to a user supplied data area that will be passed to the task +* when the task first executes. +* +* p_stk_base Pointer to the base address of the stack. +* +* stk_size Size of the stack, in number of CPU_STK elements. +* +* opt Options used to alter the behavior of OS_Task_StkInit(). +* (see OS.H for OS_TASK_OPT_xxx). +* +* Returns : Always returns the location of the new top-of-stack once the processor registers have +* been placed on the stack in the proper order. +* +* Note(s) : (1) Interrupts are enabled when task starts executing. +* +* (2) All tasks run in Thread mode, using process stack. +* +* (3) The SP must be 8-byte aligned in conforming to the Procedure Call Standard for the ARM architecture +* +* (a) Section 2.1 of the ABI for the ARM Architecture Advisory Note. SP must be 8-byte aligned +* on entry to AAPCS-Conforming functions states : +* +* The Procedure Call Standard for the ARM Architecture [AAPCS] requires primitive +* data types to be naturally aligned according to their sizes (for size = 1, 2, 4, 8 bytes). +* Doing otherwise creates more problems than it solves. +* +* In return for preserving the natural alignment of data, conforming code is permitted +* to rely on that alignment. To support aligning data allocated on the stack, the stack +* pointer (SP) is required to be 8-byte aligned on entry to a conforming function. In +* practice this requirement is met if: +* +* (1) At each call site, the current size of the calling function's stack frame is a multiple of 8 bytes. +* This places an obligation on compilers and assembly language programmers. +* +* (2) SP is a multiple of 8 when control first enters a program. +* This places an obligation on authors of low level OS, RTOS, and runtime library +* code to align SP at all points at which control first enters +* a body of (AAPCS-conforming) code. +* +* In turn, this requires the value of SP to be aligned to 0 modulo 8: +* +* (3) By exception handlers, before calling AAPCS-conforming code. +* +* (4) By OS/RTOS/run-time system code, before giving control to an application. +* +* (b) Section 2.3.1 corrective steps from the the SP must be 8-byte aligned on entry +* to AAPCS-conforming functions advisory note also states. +* +* " This requirement extends to operating systems and run-time code for all architecture versions +* prior to ARMV7 and to the A, R and M architecture profiles thereafter. Special considerations +* associated with ARMV7M are discussed in section 2.3.3" +* +* (1) Even if the SP 8-byte aligment is not a requirement for the ARMv7M profile, the stack is aligned +* to 8-byte boundaries to support legacy execution enviroments. +* +* (c) Section 5.2.1.2 from the Procedure Call Standard for the ARM +* architecture states : "The stack must also conform to the following +* constraint at a public interface: +* +* (1) SP mod 8 = 0. The stack must be double-word aligned" +* +* (d) From the ARM Technical Support Knowledge Base. 8 Byte stack aligment. +* +* "8 byte stack alignment is a requirement of the ARM Architecture Procedure +* Call Standard [AAPCS]. This specifies that functions must maintain an 8 byte +* aligned stack address (e.g. 0x00, 0x08, 0x10, 0x18, 0x20) on all external +* interfaces. In practice this requirement is met if: +* +* (1) At each external interface, the current stack pointer +* is a multiple of 8 bytes. +* +* (2) Your OS maintains 8 byte stack alignment on its external interfaces +* e.g. on task switches" +* +* (4) Exception Return Behavior(EXEC_RETURN) +* 0xFFFFFFF1 Return to Thread mode. Exception return gets state from the Main Stack. +* On Return execution uses the Main Stack. +* +* 0xFFFFFFF9 Return to Thread mode. Exception return gets state from the Main Stack. +* On Return execution uses the Main Stack. +* +* 0xFFFFFFFD Return to Thread mode. Exception return gets state from the Process Stack. +* On Return execution uses the Process Stack. +********************************************************************************************************** +*/ + +CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, + void *p_arg, + CPU_STK *p_stk_base, + CPU_STK *p_stk_limit, + CPU_STK_SIZE stk_size, + OS_OPT opt) +{ + CPU_STK *p_stk; + + + (void)opt; /* 'opt' is not used, prevent warning */ + + p_stk = &p_stk_base[stk_size]; /* Load stack pointer */ + /* Align the stack to 8-bytes. */ + p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8u); + /* Registers stacked as if auto-saved on exception */ + *(--p_stk) = (CPU_STK)0x01000000u; /* xPSR */ + *(--p_stk) = (CPU_STK)p_task; /* Entry Point */ + *(--p_stk) = (CPU_STK)OS_TaskReturn; /* R14 (LR) */ + *(--p_stk) = (CPU_STK)0x12121212u; /* R12 */ + *(--p_stk) = (CPU_STK)0x03030303u; /* R3 */ + *(--p_stk) = (CPU_STK)0x02020202u; /* R2 */ + *(--p_stk) = (CPU_STK)p_stk_limit; /* R1 */ + *(--p_stk) = (CPU_STK)p_arg; /* R0 : argument */ + /* Remaining registers saved on process stack */ + *(--p_stk) = (CPU_STK)0xFFFFFFFDuL; /* R14: EXEC_RETURN; See Note 4 */ + *(--p_stk) = (CPU_STK)0x11111111uL; /* R11 */ + *(--p_stk) = (CPU_STK)0x10101010uL; /* R10 */ + *(--p_stk) = (CPU_STK)0x09090909uL; /* R9 */ + *(--p_stk) = (CPU_STK)0x08080808uL; /* R8 */ + *(--p_stk) = (CPU_STK)0x07070707uL; /* R7 */ + *(--p_stk) = (CPU_STK)0x06060606uL; /* R6 */ + *(--p_stk) = (CPU_STK)0x05050505uL; /* R5 */ + *(--p_stk) = (CPU_STK)0x04040404uL; /* R4 */ + + return (p_stk); +} + + +/* +********************************************************************************************************* +* TASK SWITCH HOOK +* +* Description: This function is called when a task switch is performed. This allows you to perform other +* operations during a context switch. +* +* Arguments : None. +* +* Note(s) : 1) Interrupts are disabled during this call. +* 2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task +* that will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points +* to the task being switched out (i.e. the preempted task). +********************************************************************************************************* +*/ + +void OSTaskSwHook (void) +{ +#if OS_CFG_TASK_PROFILE_EN > 0u + CPU_TS ts; +#endif +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_TS int_dis_time; +#endif +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + CPU_BOOLEAN stk_status; +#endif + +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTaskSwHookPtr)(); + } +#endif + + OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr); + +#if OS_CFG_TASK_PROFILE_EN > 0u + ts = OS_TS_GET(); + if (OSTCBCurPtr != OSTCBHighRdyPtr) { + OSTCBCurPtr->CyclesDelta = ts - OSTCBCurPtr->CyclesStart; + OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta; + } + + OSTCBHighRdyPtr->CyclesStart = ts; +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + int_dis_time = CPU_IntDisMeasMaxCurReset(); /* Keep track of per-task interrupt disable time */ + if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) { + OSTCBCurPtr->IntDisTimeMax = int_dis_time; + } +#endif + +#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u + /* Keep track of per-task scheduler lock time */ + if (OSTCBCurPtr->SchedLockTimeMax < OSSchedLockTimeMaxCur) { + OSTCBCurPtr->SchedLockTimeMax = OSSchedLockTimeMaxCur; + } + OSSchedLockTimeMaxCur = (CPU_TS)0; /* Reset the per-task value */ +#endif + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + /* Check if stack overflowed. */ + stk_status = OSTaskStkRedzoneChk((OS_TCB *)0u); + if (stk_status != OS_TRUE) { + OSRedzoneHitHook(OSTCBCurPtr); + } +#endif +} + + +/* +********************************************************************************************************* +* TICK HOOK +* +* Description: This function is called every tick. +* +* Arguments : None. +* +* Note(s) : 1) This function is assumed to be called from the Tick ISR. +********************************************************************************************************* +*/ + +void OSTimeTickHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTimeTickHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* SYS TICK HANDLER +* +* Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-III tick +* interrupt. +* +* Arguments : None. +* +* Note(s) : 1) This function MUST be placed on entry 15 of the Cortex-M0 vector table. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickHandler (void) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + OSIntEnter(); /* Tell uC/OS-III that we are starting an ISR */ + CPU_CRITICAL_EXIT(); + + OSTimeTick(); /* Call uC/OS-III's OSTimeTick() */ + + OSIntExit(); /* Tell uC/OS-III that we are leaving the ISR */ +} + + +/* +********************************************************************************************************* +* INITIALIZE SYS TICK +* +* Description: Initialize the SysTick. +* +* Arguments : cnts Number of SysTick counts between two OS tick interrupts. +* +* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickInit (CPU_INT32U cnts) +{ + CPU_INT32U prio; + + + CPU_REG_SYST_RVR = cnts - 1u; /* Set Reload Register */ + + /* Set SysTick handler prio. */ + prio = CPU_REG_SCB_SHPRI3; + prio &= 0x00FFFFFFu; + prio |= (OS_CPU_CFG_SYSTICK_PRIO << 24u); + + CPU_REG_SCB_SHPRI3 = prio; + + /* Enable timer. */ + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_CLKSOURCE | + CPU_REG_SYST_CSR_ENABLE; + + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_TICKINT; /* Enable timer interrupt. */ +} + +#ifdef __cplusplus +} +#endif diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu.h b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu.h new file mode 100644 index 00000000..410328d3 --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu.h @@ -0,0 +1,183 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ARMv7-M Port +* +* File : os_cpu.h +* Version : V3.08.00 +********************************************************************************************************* +* For : ARMv7-M Cortex-M +* Mode : Thumb-2 ISA +* Toolchain : GNU C Compiler +********************************************************************************************************* +* Note(s) : (1) This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +* (2) It has been tested with the following Hardware Floating Point Unit. +* (a) Single-precision: FPv4-SP-D16-M and FPv5-SP-D16-M +* (b) Double-precision: FPv5-D16-M +********************************************************************************************************* +*/ + +#ifndef OS_CPU_H +#define OS_CPU_H + +#ifdef OS_CPU_GLOBALS +#define OS_CPU_EXT +#else +#define OS_CPU_EXT extern +#endif + + +/* +********************************************************************************************************* +* EXTERNAL C LANGUAGE LINKAGE +* +* Note(s) : (1) C++ compilers MUST 'extern'ally declare ALL C function prototypes & variable/object +* declarations for correct C language linkage. +********************************************************************************************************* +*/ + +#ifdef __cplusplus +extern "C" { /* See Note #1. */ +#endif + + +/* +********************************************************************************************************* +* DEFINES +* Note(s) : (1) Determines the interrupt programmable priority levels. This is normally specified in the +* Microcontroller reference manual. 4-bits gives us 16 programmable priority levels. +********************************************************************************************************* +*/ + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) +#define OS_CPU_ARM_FP_EN 1u +#else +#define OS_CPU_ARM_FP_EN 0u +#endif + +#ifndef CPU_CFG_KA_IPL_BOUNDARY +#error "CPU_CFG_KA_IPL_BOUNDARY not #define'd in 'cpu_cfg.h' " +#else +#if (CPU_CFG_KA_IPL_BOUNDARY == 0u) +#error "CPU_CFG_KA_IPL_BOUNDARY should be > 0 " +#endif +#endif + +#ifndef CPU_CFG_NVIC_PRIO_BITS +#error "CPU_CFG_NVIC_PRIO_BITS not #define'd in 'cpu_cfg.h' " /* See Note # 1 */ +#else +#if (CPU_CFG_KA_IPL_BOUNDARY >= (1u << CPU_CFG_NVIC_PRIO_BITS)) +#error "CPU_CFG_KA_IPL_BOUNDARY should not be set to higher than max programable priority level " +#endif +#endif + + +/* +********************************************************************************************************* +* MACROS +********************************************************************************************************* +*/ + +#define OS_TASK_SW() OSCtxSw() + +#define OS_TASK_SW_SYNC() __asm__ __volatile__ ("isb" : : : "memory") + + +/* +********************************************************************************************************* +* TIMESTAMP CONFIGURATION +* +* Note(s) : (1) OS_TS_GET() is generally defined as CPU_TS_Get32() to allow CPU timestamp timer to be of +* any data type size. +* +* (2) For architectures that provide 32-bit or higher precision free running counters +* (i.e. cycle count registers): +* +* (a) OS_TS_GET() may be defined as CPU_TS_TmrRd() to improve performance when retrieving +* the timestamp. +* +* (b) CPU_TS_TmrRd() MUST be configured to be greater or equal to 32-bits to avoid +* truncation of TS. +********************************************************************************************************* +*/ + +#if OS_CFG_TS_EN == 1u +#define OS_TS_GET() (CPU_TS)CPU_TS_TmrRd() /* See Note #2a. */ +#else +#define OS_TS_GET() (CPU_TS)0u +#endif + +#if (CPU_CFG_TS_32_EN > 0u) && \ + (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32) + /* CPU_CFG_TS_TMR_SIZE MUST be >= 32-bit (see Note #2b). */ +#error "cpu_cfg.h, CPU_CFG_TS_TMR_SIZE MUST be >= CPU_WORD_SIZE_32" +#endif + + +/* +********************************************************************************************************* +* GLOBAL VARIABLES +********************************************************************************************************* +*/ + +OS_CPU_EXT CPU_STK *OS_CPU_ExceptStkBase; + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + + /* See OS_CPU_A.ASM */ +void OSCtxSw (void); +void OSIntCtxSw (void); +void OSStartHighRdy (void); + + /* See OS_CPU_C.C */ +void OS_CPU_SysTickInit (CPU_INT32U cnts); +void OS_CPU_SysTickInitFreq(CPU_INT32U cpu_freq); + +void OS_CPU_SysTickHandler (void); +void OS_CPU_PendSVHandler (void); + +#if (OS_CPU_ARM_FP_EN > 0u) +void OS_CPU_FP_Reg_Push (CPU_STK *stkPtr); +void OS_CPU_FP_Reg_Pop (CPU_STK *stkPtr); +#endif + + +/* +********************************************************************************************************* +* EXTERNAL C LANGUAGE LINKAGE END +********************************************************************************************************* +*/ + +#ifdef __cplusplus +} /* End of 'extern'al C lang linkage. */ +#endif + + +/* +********************************************************************************************************* +* MODULE END +********************************************************************************************************* +*/ + +#endif diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_a.S b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_a.S new file mode 100644 index 00000000..7a096161 --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_a.S @@ -0,0 +1,308 @@ +@******************************************************************************************************** +@ uC/OS-III +@ The Real-Time Kernel +@ +@ Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +@ +@ SPDX-License-Identifier: APACHE-2.0 +@ +@ This software is subject to an open source license and is distributed by +@ Silicon Laboratories Inc. pursuant to the terms of the Apache License, +@ Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +@ +@******************************************************************************************************** + +@******************************************************************************************************** +@ +@ ARMv7-M Port +@ +@ For : ARMv7-M Cortex-M +@ Mode : Thumb-2 ISA +@ Toolchain : GNU C Compiler +@******************************************************************************************************** +@ Note(s) : (1) This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +@ (2) It has been tested with the following Hardware Floating Point Unit. +@ (a) Single-precision: FPv4-SP-D16-M and FPv5-SP-D16-M +@ (b) Double-precision: FPv5-D16-M +@******************************************************************************************************** + +@******************************************************************************************************** +@ PUBLIC FUNCTIONS +@******************************************************************************************************** + + @ External references. + .extern OSPrioCur + .extern OSPrioHighRdy + .extern OSTCBCurPtr + .extern OSTCBHighRdyPtr + .extern OSIntExit + .extern OSTaskSwHook + .extern OS_CPU_ExceptStkBase + .extern OS_KA_BASEPRI_Boundary + + + .global OSStartHighRdy @ Functions declared in this file + .global OSCtxSw + .global OSIntCtxSw + .global OS_CPU_PendSVHandler + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + .global OS_CPU_FP_Reg_Push + .global OS_CPU_FP_Reg_Pop +#endif + + +@******************************************************************************************************** +@ EQUATES +@******************************************************************************************************** + +.equ NVIC_INT_CTRL, 0xE000ED04 @ Interrupt control state register. +.equ NVIC_SYSPRI14, 0xE000ED22 @ System priority register (priority 14). +.equ NVIC_PENDSV_PRI, 0xFF @ PendSV priority value (lowest). +.equ NVIC_PENDSVSET, 0x10000000 @ Value to trigger PendSV exception. + + +@******************************************************************************************************** +@ CODE GENERATION DIRECTIVES +@******************************************************************************************************** + + .text + .align 2 + .thumb + .syntax unified + + +@******************************************************************************************************** +@ FLOATING POINT REGISTERS PUSH +@ void OS_CPU_FP_Reg_Push (CPU_STK *stkPtr) +@ +@ Note(s) : 1) This function saves S16-S31 registers of the Floating Point Unit. +@ +@ 2) Pseudo-code is: +@ a) Push remaining FPU regs S16-S31 on process stack; +@ b) Update OSTCBCurPtr->StkPtr; +@******************************************************************************************************** + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + +.thumb_func +OS_CPU_FP_Reg_Push: + MRS R1, PSP @ PSP is process stack pointer + CBZ R1, OS_CPU_FP_nosave @ Skip FP register save the first time + + VSTMDB R0!, {S16-S31} + LDR R1, =OSTCBCurPtr + LDR R2, [R1] + STR R0, [R2] +OS_CPU_FP_nosave: + BX LR +#endif + + +@******************************************************************************************************** +@ FLOATING POINT REGISTERS POP +@ void OS_CPU_FP_Reg_Pop (CPU_STK *stkPtr) +@ +@ Note(s) : 1) This function restores S16-S31 of the Floating Point Unit. +@ +@ 2) Pseudo-code is: +@ a) Restore regs S16-S31 of new process stack; +@ b) Update OSTCBHighRdyPtr->StkPtr pointer of new proces stack; +@******************************************************************************************************** + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + +.thumb_func +OS_CPU_FP_Reg_Pop: + VLDMIA R0!, {S16-S31} + LDR R1, =OSTCBHighRdyPtr + LDR R2, [R1] + STR R0, [R2] + BX LR +#endif + + +@******************************************************************************************************** +@ START MULTITASKING +@ void OSStartHighRdy(void) +@ +@ Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause +@ the first task to start. +@ +@ 2) During task execution, PSP is used as the stack pointer. +@ When an exception occurs, the core will switch to MSP until the exception return. +@ +@ 3) OSStartHighRdy() MUST: +@ a) Setup PendSV exception priority to lowest; +@ b) Set initial PSP to 0, to tell context switcher this is first run; +@ c) Set the main stack to OS_CPU_ExceptStkBase +@ d) Get current high priority, OSPrioCur = OSPrioHighRdy; +@ e) Get current ready thread TCB, OSTCBCurPtr = OSTCBHighRdyPtr; +@ f) Get new process SP from TCB, SP = OSTCBHighRdyPtr->StkPtr; +@ g) Restore R0-R11 and R14 from new process stack; +@ h) Enable interrupts (tasks will run with interrupts enabled). +@******************************************************************************************************** + +.thumb_func +OSStartHighRdy: + CPSID I @ Prevent interruption during context switch + MOVW R0, #:lower16:NVIC_SYSPRI14 @ Set the PendSV exception priority + MOVT R0, #:upper16:NVIC_SYSPRI14 + + MOVW R1, #:lower16:NVIC_PENDSV_PRI + MOVT R1, #:upper16:NVIC_PENDSV_PRI + STRB R1, [R0] + + MOVS R0, #0 @ Set the PSP to 0 for initial context switch call + MSR PSP, R0 + + MOVW R0, #:lower16:OS_CPU_ExceptStkBase @ Initialize the MSP to the OS_CPU_ExceptStkBase + MOVT R0, #:upper16:OS_CPU_ExceptStkBase + LDR R1, [R0] + MSR MSP, R1 + + BL OSTaskSwHook @ Call OSTaskSwHook() for FPU Push & Pop + + MOVW R0, #:lower16:OSPrioCur @ OSPrioCur = OSPrioHighRdy; + MOVT R0, #:upper16:OSPrioCur + MOVW R1, #:lower16:OSPrioHighRdy + MOVT R1, #:upper16:OSPrioHighRdy + LDRB R2, [R1] + STRB R2, [R0] + + MOVW R0, #:lower16:OSTCBCurPtr @ OSTCBCurPtr = OSTCBHighRdyPtr; + MOVT R0, #:upper16:OSTCBCurPtr + MOVW R1, #:lower16:OSTCBHighRdyPtr + MOVT R1, #:upper16:OSTCBHighRdyPtr + LDR R2, [R1] + STR R2, [R0] + + LDR R0, [R2] @ R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr; + MSR PSP, R0 @ Load PSP with new process SP + + MRS R0, CONTROL + ORR R0, R0, #2 + MSR CONTROL, R0 + ISB @ Sync instruction stream + + LDMFD SP!, {R4-R11, LR} @ Restore r4-11, lr from new process stack + LDMFD SP!, {R0-R3} @ Restore r0, r3 + LDMFD SP!, {R12, LR} @ Load R12 and LR + LDMFD SP!, {R1, R2} @ Load PC and discard xPSR + CPSIE I + BX R1 + + +@******************************************************************************************************** +@ PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() +@ PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw() +@ +@ Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function +@ triggers the PendSV exception which is where the real work is done. +@ +@ 2) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as +@ the result of an interrupt. This function simply triggers a PendSV exception which will +@ be handled when there are no more interrupts active and interrupts are enabled. +@******************************************************************************************************** + +.thumb_func +OSCtxSw: +OSIntCtxSw: + LDR R0, =NVIC_INT_CTRL @ Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + BX LR + + +@******************************************************************************************************** +@ HANDLE PendSV EXCEPTION +@ void OS_CPU_PendSVHandler(void) +@ +@ Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing +@ context switches with Cortex-M. This is because the Cortex-M auto-saves half of the +@ processor context on any exception, and restores same on return from exception. So only +@ saving of R4-R11 & R14 is required and fixing up the stack pointers. Using the PendSV exception +@ this way means that context saving and restoring is identical whether it is initiated from +@ a thread or occurs due to an interrupt or exception. +@ +@ 2) Pseudo-code is: +@ a) Get the process SP +@ b) Save remaining regs r4-r11 & r14 on process stack; +@ c) Save the process SP in its TCB, OSTCBCurPtr->OSTCBStkPtr = SP; +@ d) Call OSTaskSwHook(); +@ e) Get current high priority, OSPrioCur = OSPrioHighRdy; +@ f) Get current ready thread TCB, OSTCBCurPtr = OSTCBHighRdyPtr; +@ g) Get new process SP from TCB, SP = OSTCBHighRdyPtr->OSTCBStkPtr; +@ h) Restore R4-R11 and R14 from new process stack; +@ i) Perform exception return which will restore remaining context. +@ +@ 3) On entry into PendSV handler: +@ a) The following have been saved on the process stack (by processor): +@ xPSR, PC, LR, R12, R0-R3 +@ b) Processor mode is switched to Handler mode (from Thread mode) +@ c) Stack is Main stack (switched from Process stack) +@ d) OSTCBCurPtr points to the OS_TCB of the task to suspend +@ OSTCBHighRdyPtr points to the OS_TCB of the task to resume +@ +@ 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we +@ know that it will only be run when no other exception or interrupt is active, and +@ therefore safe to assume that context being switched out was using the process stack (PSP). +@ +@ 5) Increasing priority using a write to BASEPRI does not take effect immediately. +@ (a) IMPLICATION This erratum means that the instruction after an MSR to boost BASEPRI +@ might incorrectly be preempted by an insufficient high priority exception. +@ +@ (b) WORKAROUND The MSR to boost BASEPRI can be replaced by the following code sequence: +@ +@ CPSID i +@ MSR to BASEPRI +@ DSB +@ ISB +@ CPSIE i +@******************************************************************************************************** + +.thumb_func +OS_CPU_PendSVHandler: + CPSID I @ Cortex-M7 errata notice. See Note #5 + MOVW R2, #:lower16:OS_KA_BASEPRI_Boundary @ Set BASEPRI priority level required for exception preemption + MOVT R2, #:upper16:OS_KA_BASEPRI_Boundary + LDR R1, [R2] + MSR BASEPRI, R1 + DSB + ISB + CPSIE I + + MRS R0, PSP @ PSP is process stack pointer + STMFD R0!, {R4-R11, R14} @ Save remaining regs r4-11, R14 on process stack + + MOVW R5, #:lower16:OSTCBCurPtr @ OSTCBCurPtr->StkPtr = SP; + MOVT R5, #:upper16:OSTCBCurPtr + LDR R1, [R5] + STR R0, [R1] @ R0 is SP of process being switched out + + @ At this point, entire context of process has been saved + MOV R4, LR @ Save LR exc_return value + BL OSTaskSwHook @ Call OSTaskSwHook() for FPU Push & Pop + + MOVW R0, #:lower16:OSPrioCur @ OSPrioCur = OSPrioHighRdy; + MOVT R0, #:upper16:OSPrioCur + MOVW R1, #:lower16:OSPrioHighRdy + MOVT R1, #:upper16:OSPrioHighRdy + LDRB R2, [R1] + STRB R2, [R0] + + MOVW R1, #:lower16:OSTCBHighRdyPtr @ OSTCBCurPtr = OSTCBHighRdyPtr; + MOVT R1, #:upper16:OSTCBHighRdyPtr + LDR R2, [R1] + STR R2, [R5] + + ORR LR, R4, #0x04 @ Ensure exception return uses process stack + LDR R0, [R2] @ R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr; + LDMFD R0!, {R4-R11, R14} @ Restore r4-11, R14 from new process stack + MSR PSP, R0 @ Load PSP with new process SP + + MOV R2, #0 @ Restore BASEPRI priority level to 0 + MSR BASEPRI, R2 + BX LR @ Exception return will restore remaining context + +.end diff --git a/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c new file mode 100644 index 00000000..2a0ec6b5 --- /dev/null +++ b/rtos/uC-OS3/Ports/ARM-Cortex-M/ARMv7-M/os_cpu_c.c @@ -0,0 +1,725 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* +* ARMv7-M Port +* +* File : os_cpu_c.c +* Version : V3.08.00 +********************************************************************************************************* +* For : ARMv7-M Cortex-M +* Mode : Thumb-2 ISA +********************************************************************************************************* +* Note(s) : (1) This port supports the ARM Cortex-M3, Cortex-M4 and Cortex-M7 architectures. +* (2) It has been tested with the following Hardware Floating Point Unit. +* (a) Single-precision: FPv4-SP-D16-M and FPv5-SP-D16-M +* (b) Double-precision: FPv5-D16-M +********************************************************************************************************* +*/ + +#define OS_CPU_GLOBALS + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_cpu_c__c = "$Id: $"; +#endif + + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include "../../../Source/os.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* +********************************************************************************************************* +* LOCAL GLOBAL VARIABLES +********************************************************************************************************* +*/ + +CPU_INT32U OS_KA_BASEPRI_Boundary; /* Base Priority boundary. */ + + +/* +********************************************************************************************************* +* FLOATING POINT DEFINES +********************************************************************************************************* +*/ + +#define CPU_REG_FP_FPCCR (*((CPU_REG32 *)0xE000EF34uL)) /* Floating-Point Context Control Reg. */ + + /* Enabled FP lazy stacking and enable .. */ + /* ..automatic state saving. */ +#define CPU_REG_FPCCR_LAZY_STK 0xC0000000uL + + +/* +********************************************************************************************************* +* IDLE TASK HOOK +* +* Description: This function is called by the idle task. This hook has been added to allow you to do +* such things as STOP the CPU to conserve power. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSIdleTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppIdleTaskHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* OS INITIALIZATION HOOK +* +* Description: This function is called by OSInit() at the beginning of OSInit(). +* +* Arguments : None. +* +* Note(s) : 1) When using hardware floating point please do the following during the reset handler: +* a) Set full access for CP10 & CP11 bits in CPACR register. +* b) Set bits ASPEN and LSPEN in FPCCR register. +********************************************************************************************************* +*/ + +void OSInitHook (void) +{ +#if (OS_CPU_ARM_FP_EN > 0u) + CPU_INT32U reg_val; +#endif + /* 8-byte align the ISR stack. */ + OS_CPU_ExceptStkBase = (CPU_STK *)(OSCfg_ISRStkBasePtr + OSCfg_ISRStkSize); + OS_CPU_ExceptStkBase = (CPU_STK *)((CPU_STK)(OS_CPU_ExceptStkBase) & 0xFFFFFFF8); + +#if (OS_CPU_ARM_FP_EN > 0u) + reg_val = CPU_REG_FP_FPCCR; /* Check the floating point mode. */ + if ((reg_val & CPU_REG_FPCCR_LAZY_STK) != CPU_REG_FPCCR_LAZY_STK) { + while (1u) { /* See Note (1). */ + ; + } + } +#endif + /* Set BASEPRI boundary from the configuration. */ + OS_KA_BASEPRI_Boundary = (CPU_INT32U)(CPU_CFG_KA_IPL_BOUNDARY << (8u - CPU_CFG_NVIC_PRIO_BITS)); +} + + +/* +********************************************************************************************************* +* REDZONE HIT HOOK +* +* Description: This function is called when a task's stack overflowed. +* +* Arguments : p_tcb Pointer to the task control block of the offending task. NULL if ISR. +* +* Note(s) : None. +********************************************************************************************************* +*/ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void OSRedzoneHitHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppRedzoneHitHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppRedzoneHitHookPtr)(p_tcb); + } else { + CPU_SW_EXCEPTION(;); + } +#else + (void)p_tcb; /* Prevent compiler warning */ + CPU_SW_EXCEPTION(;); +#endif +} +#endif + + +/* +********************************************************************************************************* +* STATISTIC TASK HOOK +* +* Description: This function is called every second by uC/OS-III's statistics task. This allows your +* application to add functionality to the statistics task. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSStatTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppStatTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppStatTaskHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* TASK CREATION HOOK +* +* Description: This function is called when a task is created. +* +* Arguments : p_tcb Pointer to the task control block of the task being created. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskCreateHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskCreateHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* TASK DELETION HOOK +* +* Description: This function is called when a task is deleted. +* +* Arguments : p_tcb Pointer to the task control block of the task being deleted. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskDelHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskDelHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskDelHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* TASK RETURN HOOK +* +* Description: This function is called if a task accidentally returns. In other words, a task should +* either be an infinite loop or delete itself when done. +* +* Arguments : p_tcb Pointer to the task control block of the task that is returning. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskReturnHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskReturnHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskReturnHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* INITIALIZE A TASK'S STACK +* +* Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the +* stack frame of the task being created. This function is highly processor specific. +* +* Arguments : p_task Pointer to the task entry point address. +* +* p_arg Pointer to a user supplied data area that will be passed to the task +* when the task first executes. +* +* p_stk_base Pointer to the base address of the stack. +* +* stk_size Size of the stack, in number of CPU_STK elements. +* +* opt Options used to alter the behavior of OS_Task_StkInit(). +* (see OS.H for OS_TASK_OPT_xxx). +* +* Returns : Always returns the location of the new top-of-stack once the processor registers have +* been placed on the stack in the proper order. +* +* Note(s) : (1) Interrupts are enabled when task starts executing. +* +* (2) All tasks run in Thread mode, using process stack. +* +* (3) There are two different stack frames depending on whether the Floating-Point(FP) +* co-processor is enabled or not. +* +* (a) The stack frame shown in the diagram is used when the Co-processor Access Control +* Register(CPACR) is disabling the Floating Point Unit. In this case, the FP +* registers(S0- S31) & FP Status Control(FPSCR) register are not saved in the stack frame. +* +* (b) The stack frame shown in the diagram is used when the Floating Point Unit is enabled, +* that is, CP10 and CP11 field in CPACR are ones and FPCCR sets bits ASPEN and LSPEN to 1. +* +* (1) When enabling the FPU through CPACR, make sure to set bits ASPEN and LSPEN in the +* Floating-Point Context Control Register (FPCCR). +* +* +-------------+ +* | | +* +-------------+ +* | | +* +-------------+ +* | FPSCR | +* +-------------+ +* | S15 | +* +-------------+ +* | S14 | +* +-------------+ +* | S13 | +* +-------------+ +* . +* . +* . +* +-------------+ +* | S2 | +* +-------------+ +* | S1 | +* +-------------+ +-------------+ +* | | | S0 | +* +-------------+ +-------------+ +* | xPSR | | xPSR | +* +-------------+ +-------------+ +* | Return Addr | | Return Addr | +* +-------------+ +-------------+ +* | LR(R14) | | LR(R14) | +* +-------------+ +-------------+ +* | R12 | | R12 | +* +-------------+ +-------------+ +* | R3 | | R3 | +* +-------------+ +-------------+ +* | R2 | | R0 | +* +-------------+ +-------------+ +* | R1 | | R1 | +* +-------------+ +-------------+ +* | R0 | | R0 | +* +-------------+ +-------------+ +* | EXEC_RETURN | | EXEC_RETURN | +* +-------------+ +-------------+ +* | R11 | | R11 | +* +-------------+ +-------------+ +* | R10 | | R10 | +* +-------------+ +-------------+ +* | R9 | | R9 | +* +-------------+ +-------------+ +* | R8 | | R8 | +* +-------------+ +-------------+ +* | R7 | | R7 | +* +-------------+ +-------------+ +* | R6 | | R6 | +* +-------------+ +-------------+ +* | R5 | | R5 | +* +-------------+ +-------------+ +* | R4 | | R4 | +* +-------------+ +-------------+ +* (a) | S31 | +* +-------------+ +* | S30 | +* +-------------+ +* | S29 | + +-------------+ +* . +* . +* . +* +-------------+ +* | S17 | + +-------------+ +* | S16 | +* +-------------+ +* (b) +* +* (4) The SP must be 8-byte aligned in conforming to the Procedure Call Standard for the ARM architecture +* +* (a) Section 2.1 of the ABI for the ARM Architecture Advisory Note. SP must be 8-byte aligned +* on entry to AAPCS-Conforming functions states : +* +* The Procedure Call Standard for the ARM Architecture [AAPCS] requires primitive +* data types to be naturally aligned according to their sizes (for size = 1, 2, 4, 8 bytes). +* Doing otherwise creates more problems than it solves. +* +* In return for preserving the natural alignment of data, conforming code is permitted +* to rely on that alignment. To support aligning data allocated on the stack, the stack +* pointer (SP) is required to be 8-byte aligned on entry to a conforming function. In +* practice this requirement is met if: +* +* (1) At each call site, the current size of the calling function's stack frame is a multiple of 8 bytes. +* This places an obligation on compilers and assembly language programmers. +* +* (2) SP is a multiple of 8 when control first enters a program. +* This places an obligation on authors of low level OS, RTOS, and runtime library +* code to align SP at all points at which control first enters +* a body of (AAPCS-conforming) code. +* +* In turn, this requires the value of SP to be aligned to 0 modulo 8: +* +* (3) By exception handlers, before calling AAPCS-conforming code. +* +* (4) By OS/RTOS/run-time system code, before giving control to an application. +* +* (b) Section 2.3.1 corrective steps from the the SP must be 8-byte aligned on entry +* to AAPCS-conforming functions advisory note also states. +* +* " This requirement extends to operating systems and run-time code for all architecture versions +* prior to ARMV7 and to the A, R and M architecture profiles thereafter. Special considerations +* associated with ARMV7M are discussed in section 2.3.3" +* +* (1) Even if the SP 8-byte aligment is not a requirement for the ARMv7M profile, the stack is aligned +* to 8-byte boundaries to support legacy execution enviroments. +* +* (c) Section 5.2.1.2 from the Procedure Call Standard for the ARM +* architecture states : "The stack must also conform to the following +* constraint at a public interface: +* +* (1) SP mod 8 = 0. The stack must be double-word aligned" +* +* (d) From the ARM Technical Support Knowledge Base. 8 Byte stack aligment. +* +* "8 byte stack alignment is a requirement of the ARM Architecture Procedure +* Call Standard [AAPCS]. This specifies that functions must maintain an 8 byte +* aligned stack address (e.g. 0x00, 0x08, 0x10, 0x18, 0x20) on all external +* interfaces. In practice this requirement is met if: +* +* (1) At each external interface, the current stack pointer +* is a multiple of 8 bytes. +* +* (2) Your OS maintains 8 byte stack alignment on its external interfaces +* e.g. on task switches" +* +* (5) Exception Return Behavior(EXEC_RETURN) +* 0xFFFFFFFD Return to Thread mode, exception return uses non-floating point state +* from the PSP and execution uses PSP after return. +* +* 0xFFFFFFED Return to Thread mode, exception return uses floating point state +* from the PSP and execution uses PSP after return. +********************************************************************************************************** +*/ + +CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, + void *p_arg, + CPU_STK *p_stk_base, + CPU_STK *p_stk_limit, + CPU_STK_SIZE stk_size, + OS_OPT opt) +{ + CPU_STK *p_stk; + + + (void)opt; /* 'opt' is not used, prevent warning */ + + p_stk = &p_stk_base[stk_size]; /* Load stack pointer */ + /* Align the stack to 8-bytes. */ + p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8u); + /* Registers stacked as if auto-saved on exception */ +#if (OS_CPU_ARM_FP_EN > 0u) /* FPU auto-saved registers. */ + --p_stk; + *(--p_stk) = (CPU_STK)0x02000000u; /* FPSCR */ + /* Initialize S0-S15 floating point registers */ + *(--p_stk) = (CPU_STK)0x41700000u; /* S15 */ + *(--p_stk) = (CPU_STK)0x41600000u; /* S14 */ + *(--p_stk) = (CPU_STK)0x41500000u; /* S13 */ + *(--p_stk) = (CPU_STK)0x41400000u; /* S12 */ + *(--p_stk) = (CPU_STK)0x41300000u; /* S11 */ + *(--p_stk) = (CPU_STK)0x41200000u; /* S10 */ + *(--p_stk) = (CPU_STK)0x41100000u; /* S9 */ + *(--p_stk) = (CPU_STK)0x41000000u; /* S8 */ + *(--p_stk) = (CPU_STK)0x40E00000u; /* S7 */ + *(--p_stk) = (CPU_STK)0x40C00000u; /* S6 */ + *(--p_stk) = (CPU_STK)0x40A00000u; /* S5 */ + *(--p_stk) = (CPU_STK)0x40800000u; /* S4 */ + *(--p_stk) = (CPU_STK)0x40400000u; /* S3 */ + *(--p_stk) = (CPU_STK)0x40000000u; /* S2 */ + *(--p_stk) = (CPU_STK)0x3F800000u; /* S1 */ + *(--p_stk) = (CPU_STK)0x00000000u; /* S0 */ +#endif + *(--p_stk) = (CPU_STK)0x01000000u; /* xPSR */ + *(--p_stk) = (CPU_STK)p_task; /* Entry Point */ + *(--p_stk) = (CPU_STK)OS_TaskReturn; /* R14 (LR) */ + *(--p_stk) = (CPU_STK)0x12121212u; /* R12 */ + *(--p_stk) = (CPU_STK)0x03030303u; /* R3 */ + *(--p_stk) = (CPU_STK)0x02020202u; /* R2 */ + *(--p_stk) = (CPU_STK)p_stk_limit; /* R1 */ + *(--p_stk) = (CPU_STK)p_arg; /* R0 : argument */ + +#if (OS_CPU_ARM_FP_EN > 0u) + *(--p_stk) = (CPU_STK)0xFFFFFFEDuL; /* R14: EXEC_RETURN; See Note 5 */ +#else + *(--p_stk) = (CPU_STK)0xFFFFFFFDuL; /* R14: EXEC_RETURN; See Note 5 */ +#endif + /* Remaining registers saved on process stack */ + *(--p_stk) = (CPU_STK)0x11111111uL; /* R11 */ + *(--p_stk) = (CPU_STK)0x10101010uL; /* R10 */ + *(--p_stk) = (CPU_STK)0x09090909uL; /* R9 */ + *(--p_stk) = (CPU_STK)0x08080808uL; /* R8 */ + *(--p_stk) = (CPU_STK)0x07070707uL; /* R7 */ + *(--p_stk) = (CPU_STK)0x06060606uL; /* R6 */ + *(--p_stk) = (CPU_STK)0x05050505uL; /* R5 */ + *(--p_stk) = (CPU_STK)0x04040404uL; /* R4 */ + +#if (OS_CPU_ARM_FP_EN > 0u) + /* Initialize S16-S31 floating point registers */ + *(--p_stk) = (CPU_STK)0x41F80000u; /* S31 */ + *(--p_stk) = (CPU_STK)0x41F00000u; /* S30 */ + *(--p_stk) = (CPU_STK)0x41E80000u; /* S29 */ + *(--p_stk) = (CPU_STK)0x41E00000u; /* S28 */ + *(--p_stk) = (CPU_STK)0x41D80000u; /* S27 */ + *(--p_stk) = (CPU_STK)0x41D00000u; /* S26 */ + *(--p_stk) = (CPU_STK)0x41C80000u; /* S25 */ + *(--p_stk) = (CPU_STK)0x41C00000u; /* S24 */ + *(--p_stk) = (CPU_STK)0x41B80000u; /* S23 */ + *(--p_stk) = (CPU_STK)0x41B00000u; /* S22 */ + *(--p_stk) = (CPU_STK)0x41A80000u; /* S21 */ + *(--p_stk) = (CPU_STK)0x41A00000u; /* S20 */ + *(--p_stk) = (CPU_STK)0x41980000u; /* S19 */ + *(--p_stk) = (CPU_STK)0x41900000u; /* S18 */ + *(--p_stk) = (CPU_STK)0x41880000u; /* S17 */ + *(--p_stk) = (CPU_STK)0x41800000u; /* S16 */ +#endif + + return (p_stk); +} + + +/* +********************************************************************************************************* +* TASK SWITCH HOOK +* +* Description: This function is called when a task switch is performed. This allows you to perform other +* operations during a context switch. +* +* Arguments : None. +* +* Note(s) : 1) Interrupts are disabled during this call. +* 2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task +* that will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points +* to the task being switched out (i.e. the preempted task). +********************************************************************************************************* +*/ + +void OSTaskSwHook (void) +{ +#if OS_CFG_TASK_PROFILE_EN > 0u + CPU_TS ts; +#endif +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_TS int_dis_time; +#endif +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + CPU_BOOLEAN stk_status; +#endif + +#if (OS_CPU_ARM_FP_EN > 0u) + OS_CPU_FP_Reg_Push(OSTCBCurPtr->StkPtr); /* Push the FP registers of the current task. */ +#endif + +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTaskSwHookPtr)(); + } +#endif + + OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr); + +#if OS_CFG_TASK_PROFILE_EN > 0u + ts = OS_TS_GET(); + if (OSTCBCurPtr != OSTCBHighRdyPtr) { + OSTCBCurPtr->CyclesDelta = ts - OSTCBCurPtr->CyclesStart; + OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta; + } + + OSTCBHighRdyPtr->CyclesStart = ts; +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + int_dis_time = CPU_IntDisMeasMaxCurReset(); /* Keep track of per-task interrupt disable time */ + if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) { + OSTCBCurPtr->IntDisTimeMax = int_dis_time; + } +#endif + +#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u + /* Keep track of per-task scheduler lock time */ + if (OSTCBCurPtr->SchedLockTimeMax < OSSchedLockTimeMaxCur) { + OSTCBCurPtr->SchedLockTimeMax = OSSchedLockTimeMaxCur; + } + OSSchedLockTimeMaxCur = (CPU_TS)0; /* Reset the per-task value */ +#endif + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + /* Check if stack overflowed. */ + stk_status = OSTaskStkRedzoneChk((OS_TCB *)0u); + if (stk_status != OS_TRUE) { + OSRedzoneHitHook(OSTCBCurPtr); + } +#endif + +#if (OS_CPU_ARM_FP_EN > 0u) + OS_CPU_FP_Reg_Pop(OSTCBHighRdyPtr->StkPtr); /* Pop the FP registers of the highest ready task. */ +#endif +} + + +/* +********************************************************************************************************* +* TICK HOOK +* +* Description: This function is called every tick. +* +* Arguments : None. +* +* Note(s) : 1) This function is assumed to be called from the Tick ISR. +********************************************************************************************************* +*/ + +void OSTimeTickHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTimeTickHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* SYS TICK HANDLER +* +* Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-III tick +* interrupt. +* +* Arguments : None. +* +* Note(s) : 1) This function MUST be placed on entry 15 of the Cortex-M vector table. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickHandler (void) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + OSIntEnter(); /* Tell uC/OS-III that we are starting an ISR */ + CPU_CRITICAL_EXIT(); + + OSTimeTick(); /* Call uC/OS-III's OSTimeTick() */ + + OSIntExit(); /* Tell uC/OS-III that we are leaving the ISR */ +} + + +/* +********************************************************************************************************* +* INITIALIZE SYS TICK +* +* Description: Initialize the SysTick using the CPU clock frequency. +* +* Arguments : cpu_freq CPU clock frequency. +* +* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization. +* +* 2) Either OS_CPU_SysTickInitFreq or OS_CPU_SysTickInit() can be called. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickInitFreq (CPU_INT32U cpu_freq) +{ +#if (OS_CFG_TICK_EN > 0u) + CPU_INT32U cnts; + + + cnts = (cpu_freq / (CPU_INT32U)OSCfg_TickRate_Hz); /* Determine nbr SysTick cnts between two OS tick intr. */ + + OS_CPU_SysTickInit(cnts); +#else + (void)cpu_freq; +#endif +} + + +/* +********************************************************************************************************* +* INITIALIZE SYS TICK +* +* Description: Initialize the SysTick using the number of countes between two ticks. +* +* Arguments : cnts Number of SysTick counts between two OS tick interrupts. +* +* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization. +* +* 2) Either OS_CPU_SysTickInitFreq or OS_CPU_SysTickInit() can be called. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickInit (CPU_INT32U cnts) +{ +#if (OS_CFG_TICK_EN > 0u) + CPU_INT32U prio; + CPU_INT32U basepri; + + + /* Set BASEPRI boundary from the configuration. */ + basepri = (CPU_INT32U)(CPU_CFG_KA_IPL_BOUNDARY << (8u - CPU_CFG_NVIC_PRIO_BITS)); + CPU_REG_SYST_RVR = cnts - 1u; /* Set Reload Register */ + + /* Set SysTick handler prio. */ + prio = CPU_REG_SCB_SHPRI3; + prio &= 0x00FFFFFFu; + prio |= (basepri << 24u); + + CPU_REG_SCB_SHPRI3 = prio; + + /* Enable timer. */ + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_CLKSOURCE | + CPU_REG_SYST_CSR_ENABLE; + + CPU_REG_SYST_CSR |= CPU_REG_SYST_CSR_TICKINT; /* Enable timer interrupt. */ +#else + (void)cnts; +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/rtos/uC-OS3/Ports/POSIX/os_cpu.h b/rtos/uC-OS3/Ports/POSIX/os_cpu.h new file mode 100644 index 00000000..24dfb5d6 --- /dev/null +++ b/rtos/uC-OS3/Ports/POSIX/os_cpu.h @@ -0,0 +1,94 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* POSIX GNU Port +* +* File : os_cpu.h +* Version : V3.08.00 +********************************************************************************************************* +* For : POSIX +* Toolchain : GNU +********************************************************************************************************* +*/ + +#ifndef OS_CPU_H +#define OS_CPU_H + +#ifdef OS_CPU_GLOBALS +#define OS_CPU_EXT +#else +#define OS_CPU_EXT extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* +********************************************************************************************************* +* MACROS +********************************************************************************************************* +*/ + +#define OS_TASK_SW() OSCtxSw() + +/* +********************************************************************************************************* +* TIMESTAMP CONFIGURATION +* +* Note(s) : (1) OS_TS_GET() is generally defined as CPU_TS_Get32() to allow CPU timestamp timer to be of +* any data type size. +* +* (2) For architectures that provide 32-bit or higher precision free running counters +* (i.e. cycle count registers): +* +* (a) OS_TS_GET() may be defined as CPU_TS_TmrRd() to improve performance when retrieving +* the timestamp. +* +* (b) CPU_TS_TmrRd() MUST be configured to be greater or equal to 32-bits to avoid +* truncation of TS. +********************************************************************************************************* +*/ + +#if OS_CFG_TS_EN == 1u +#define OS_TS_GET() (CPU_TS)CPU_TS_TmrRd() /* See Note #2a. */ +#else +#define OS_TS_GET() (CPU_TS)0u +#endif + + +/* +********************************************************************************************************* +* FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +void OSCtxSw (void); +void OSIntCtxSw (void); + +void OSStartHighRdy (void); + +void OS_CPU_SysTickInit (void); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rtos/uC-OS3/Ports/POSIX/os_cpu_c.c b/rtos/uC-OS3/Ports/POSIX/os_cpu_c.c new file mode 100644 index 00000000..c1214353 --- /dev/null +++ b/rtos/uC-OS3/Ports/POSIX/os_cpu_c.c @@ -0,0 +1,730 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* POSIX GNU Port +* +* File : os_cpu_c.c +* Version : V3.08.00 +********************************************************************************************************* +* For : POSIX +* Toolchain : GNU +********************************************************************************************************* +*/ + + +#define OS_CPU_GLOBALS +#define _GNU_SOURCE + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_cpu_c__c = "$Id: $"; +#endif + +/* +********************************************************************************************************* +* INCLUDE FILES +********************************************************************************************************* +*/ + +#include "../../Source/os.h" +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +********************************************************************************************************* +* LOCAL DEFINES +********************************************************************************************************* +*/ + +#define THREAD_CREATE_PRIO 50u /* Tasks underlying posix threads prio. */ + + /* Err handling convenience macro. */ +#define ERR_CHK(func) do {int res = func; \ + if (res != 0u) { \ + printf("Error in call '%s' from %s(): %s­\r\n", #func, __FUNCTION__, strerror(res)); \ + perror(" \\->'errno' indicates (might not be relevant if function doesn't use 'errno')"); \ + raise(SIGABRT); \ + } \ + } while(0) + +/* +********************************************************************************************************* +* LOCAL DATA TYPES +********************************************************************************************************* +*/ + +typedef struct os_tcb_ext_posix { + pthread_t Thread; + pid_t ProcessId; + sem_t InitSem; + sem_t Sem; +} OS_TCB_EXT_POSIX; + + +/* +********************************************************************************************************* +* LOCAL FUNCTION PROTOTYPES +********************************************************************************************************* +*/ + +static void *OSTaskPosix (void *p_arg); + +static void OSTaskTerminate (OS_TCB *p_tcb); + +static void OSThreadCreate (pthread_t *p_thread, + void *p_task, + void *p_arg, + int prio); + +static void OSTimeTickHandler (void); + + +/* +********************************************************************************************************* +* LOCAL VARIABLES +********************************************************************************************************* +*/ + + /* Tick timer cfg. */ +static CPU_TMR_INTERRUPT OSTickTmrInterrupt = { .Interrupt.NamePtr = "Tick tmr interrupt", + .Interrupt.Prio = 10u, + .Interrupt.TraceEn = 0u, + .Interrupt.ISR_Fnct = OSTimeTickHandler, + .Interrupt.En = 1u, + .OneShot = 0u, + .PeriodSec = 0u, + .PeriodMuSec = (1000000u / OS_CFG_TICK_RATE_HZ) + }; + + +/* +********************************************************************************************************* +* LOCAL CONFIGURATION ERRORS +********************************************************************************************************* +*/ + +#if (OS_CFG_TICK_RATE_HZ > 100u) +#warning "Time accuracy cannot be maintained with OS_CFG_TICK_RATE_HZ > 100u.\n\n", +#endif + + +/* +********************************************************************************************************* +* IDLE TASK HOOK +* +* Description: This function is called by the idle task. This hook has been added to allow you to do +* such things as STOP the CPU to conserve power. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSIdleTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppIdleTaskHookPtr)(); + } +#endif + + sleep(1u); /* Reduce CPU utilization. */ +} + + +/* +********************************************************************************************************* +* OS INITIALIZATION HOOK +* +* Description: This function is called by OSInit() at the beginning of OSInit(). +* +* Arguments : None. +* +* Note(s) : 1) Interrupts should be disabled during this call. +********************************************************************************************************* +*/ + + +void OSInitHook (void) +{ + struct rlimit rtprio_limits; + + + ERR_CHK(getrlimit(RLIMIT_RTPRIO, &rtprio_limits)); + if (rtprio_limits.rlim_cur != RLIM_INFINITY) { + printf("Error: RTPRIO limit is too low. Set to 'unlimited' via 'ulimit -r' or /etc/security/limits.conf\r\n"); + exit(-1); + } + + CPU_IntInit(); /* Initialize critical section objects. */ +} + + +/* +********************************************************************************************************* +* STATISTIC TASK HOOK +* +* Description: This function is called every second by uC/OS-III's statistics task. This allows your +* application to add functionality to the statistics task. +* +* Arguments : None. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSStatTaskHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppStatTaskHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppStatTaskHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* TASK CREATION HOOK +* +* Description: This function is called when a task is created. +* +* Arguments : p_tcb Pointer to the task control block of the task being created. +* +* Note(s) : 1) Interrupts are disabled during this call. +********************************************************************************************************* +*/ + +void OSTaskCreateHook (OS_TCB *p_tcb) +{ + OS_TCB_EXT_POSIX *p_tcb_ext; + int ret; + + +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskCreateHookPtr)(p_tcb); + } +#endif + + p_tcb_ext = malloc(sizeof(OS_TCB_EXT_POSIX)); + p_tcb->ExtPtr = p_tcb_ext; + + ERR_CHK(sem_init(&p_tcb_ext->InitSem, 0u, 0u)); + ERR_CHK(sem_init(&p_tcb_ext->Sem, 0u, 0u)); + + OSThreadCreate(&p_tcb_ext->Thread, OSTaskPosix, p_tcb, THREAD_CREATE_PRIO); + + do { + ret = sem_wait(&p_tcb_ext->InitSem); /* Wait for init. */ + if (ret != 0 && errno != EINTR) { + raise(SIGABRT); + } + } while (ret != 0); +} + + +/* +********************************************************************************************************* +* TASK DELETION HOOK +* +* Description: This function is called when a task is deleted. +* +* Arguments : p_tcb Pointer to the task control block of the task being deleted. +* +* Note(s) : 1) Interrupts are disabled during this call. +********************************************************************************************************* +*/ + +void OSTaskDelHook (OS_TCB *p_tcb) +{ + OS_TCB_EXT_POSIX *p_tcb_ext = (OS_TCB_EXT_POSIX *)p_tcb->ExtPtr; + pthread_t self; + CPU_BOOLEAN same; + + +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskDelHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskDelHookPtr)(p_tcb); + } +#endif + + self = pthread_self(); + same = (pthread_equal(self, p_tcb_ext->Thread) != 0u); + if (same != 1u) { + ERR_CHK(pthread_cancel(p_tcb_ext->Thread)); + } + + OSTaskTerminate(p_tcb); +} + + +/* +********************************************************************************************************* +* TASK RETURN HOOK +* +* Description: This function is called if a task accidentally returns. In other words, a task should +* either be an infinite loop or delete itself when done. +* +* Arguments : p_tcb Pointer to the task control block of the task that is returning. +* +* Note(s) : None. +********************************************************************************************************* +*/ + +void OSTaskReturnHook (OS_TCB *p_tcb) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskReturnHookPtr != (OS_APP_HOOK_TCB)0) { + (*OS_AppTaskReturnHookPtr)(p_tcb); + } +#else + (void)p_tcb; /* Prevent compiler warning */ +#endif +} + + +/* +********************************************************************************************************* +* INITIALIZE A TASK'S STACK +* +* Description: This function is called by OS_Task_Create() or OSTaskCreateExt() to initialize the stack +* frame of the task being created. This function is highly processor specific. +* +* Arguments : p_task Pointer to the task entry point address. +* +* p_arg Pointer to a user supplied data area that will be passed to the task +* when the task first executes. +* +* p_stk_base Pointer to the base address of the stack. +* +* stk_size Size of the stack, in number of CPU_STK elements. +* +* opt Options used to alter the behavior of OS_Task_StkInit(). +* (see OS.H for OS_TASK_OPT_xxx). +* +* Returns : Always returns the location of the new top-of-stack' once the processor registers have +* been placed on the stack in the proper order. +********************************************************************************************************* +*/ + +CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, + void *p_arg, + CPU_STK *p_stk_base, + CPU_STK *p_stk_limit, + CPU_STK_SIZE stk_size, + OS_OPT opt) +{ + return (p_stk_base); +} + + +/* +********************************************************************************************************* +* TASK SWITCH HOOK +* +* Description: This function is called when a task switch is performed. This allows you to perform other +* operations during a context switch. +* +* Arguments : None. +* +* Note(s) : 1) Interrupts are disabled during this call. +* 2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task +* that will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points +* to the task being switched out (i.e. the preempted task). +********************************************************************************************************* +*/ + +void OSTaskSwHook (void) +{ +#if OS_CFG_TASK_PROFILE_EN > 0u + CPU_TS ts; +#endif +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_TS int_dis_time; +#endif + + +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTaskSwHookPtr)(); + } +#endif + +#if OS_CFG_TASK_PROFILE_EN > 0u + ts = OS_TS_GET(); + if (OSTCBCurPtr != OSTCBHighRdyPtr) { + OSTCBCurPtr->CyclesDelta = ts - OSTCBCurPtr->CyclesStart; + OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta; + } + + OSTCBHighRdyPtr->CyclesStart = ts; +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + int_dis_time = CPU_IntDisMeasMaxCurReset(); /* Keep track of per-task interrupt disable time */ + if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) { + OSTCBCurPtr->IntDisTimeMax = int_dis_time; + } +#endif + +#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u + /* Keep track of per-task scheduler lock time */ + if (OSTCBCurPtr->SchedLockTimeMax < (CPU_TS)OSSchedLockTimeMaxCur) { + OSTCBCurPtr->SchedLockTimeMax = (CPU_TS)OSSchedLockTimeMaxCur; + } + OSSchedLockTimeMaxCur = (CPU_TS)0; /* Reset the per-task value */ +#endif +} + + +/* +********************************************************************************************************* +* TICK HOOK +* +* Description: This function is called every tick. +* +* Arguments : None. +* +* Note(s) : 1) This function is assumed to be called from the Tick ISR. +********************************************************************************************************* +*/ + +void OSTimeTickHook (void) +{ +#if OS_CFG_APP_HOOKS_EN > 0u + if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) { + (*OS_AppTimeTickHookPtr)(); + } +#endif +} + + +/* +********************************************************************************************************* +* START HIGHEST PRIORITY TASK READY-TO-RUN +* +* Description: This function is called by OSStart() to start the highest priority task that was created +* by your application before calling OSStart(). +* +* Arguments : None. +* +* Note(s) : 1) OSStartHighRdy() MUST: +* a) Call OSTaskSwHook() then, +* b) Switch to the highest priority task. +********************************************************************************************************* +*/ + +void OSStartHighRdy (void) +{ + OS_TCB_EXT_POSIX *p_tcb_ext; + sigset_t sig_set; + int signo; + + + OSTaskSwHook(); + + p_tcb_ext = (OS_TCB_EXT_POSIX *)OSTCBCurPtr->ExtPtr; + + CPU_INT_DIS(); + + ERR_CHK(sem_post(&p_tcb_ext->Sem)); + + ERR_CHK(sigemptyset(&sig_set)); + ERR_CHK(sigaddset(&sig_set, SIGTERM)); + ERR_CHK(sigwait(&sig_set, &signo)); +} + + +/* +********************************************************************************************************* +* TASK LEVEL CONTEXT SWITCH +* +* Description: This function is called when a task makes a higher priority task ready-to-run. +* +* Arguments : None. +* +* Note(s) : 1) Upon entry, +* OSTCBCur points to the OS_TCB of the task to suspend +* OSTCBHighRdy points to the OS_TCB of the task to resume +* +* 2) OSCtxSw() MUST: +* a) Save processor registers then, +* b) Save current task's stack pointer into the current task's OS_TCB, +* c) Call OSTaskSwHook(), +* d) Set OSTCBCur = OSTCBHighRdy, +* e) Set OSPrioCur = OSPrioHighRdy, +* f) Switch to the highest priority task. +* +* pseudo-code: +* void OSCtxSw (void) +* { +* Save processor registers; +* +* OSTCBCur->OSTCBStkPtr = SP; +* +* OSTaskSwHook(); +* +* OSTCBCur = OSTCBHighRdy; +* OSPrioCur = OSPrioHighRdy; +* +* Restore processor registers from (OSTCBHighRdy->OSTCBStkPtr); +* } +********************************************************************************************************* +*/ + +void OSCtxSw (void) +{ + OS_TCB_EXT_POSIX *p_tcb_ext_old; + OS_TCB_EXT_POSIX *p_tcb_ext_new; + int ret; + CPU_BOOLEAN detach = 0u; + + + OSTaskSwHook(); + + p_tcb_ext_new = (OS_TCB_EXT_POSIX *)OSTCBHighRdyPtr->ExtPtr; + p_tcb_ext_old = (OS_TCB_EXT_POSIX *)OSTCBCurPtr->ExtPtr; + + if (OSTCBCurPtr->TaskState == OS_TASK_STATE_DEL) { + detach = 1u; + } + + OSTCBCurPtr = OSTCBHighRdyPtr; + OSPrioCur = OSPrioHighRdy; + + ERR_CHK(sem_post(&p_tcb_ext_new->Sem)); + + if (detach == 0u) { + do { + ret = sem_wait(&p_tcb_ext_old->Sem); + if (ret != 0 && errno != EINTR) { + raise(SIGABRT); + } + } while (ret != 0); + } +} + + +/* +********************************************************************************************************* +* INTERRUPT LEVEL CONTEXT SWITCH +* +* Description: This function is called by OSIntExit() to perform a context switch from an ISR. +* +* Arguments : None. +* +* Note(s) : 1) OSIntCtxSw() MUST: +* a) Call OSTaskSwHook() then, +* b) Set OSTCBCurPtr = OSTCBHighRdyPtr, +* c) Set OSPrioCur = OSPrioHighRdy, +* d) Switch to the highest priority task. +* +* 2) OSIntCurTaskSuspend() MUST be called prior to OSIntEnter(). +* +* 3) OSIntCurTaskResume() MUST be called after OSIntExit() to switch to the highest +* priority task. +********************************************************************************************************* +*/ + +void OSIntCtxSw (void) +{ + if (OSTCBCurPtr != OSTCBHighRdyPtr) { + OSCtxSw(); + } +} + +/* +********************************************************************************************************* +* INITIALIZE SYS TICK +* +* Description: Initialize the SysTick. +* +* Arguments : none. +* +* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization. +********************************************************************************************************* +*/ + +void OS_CPU_SysTickInit (void) +{ + CPU_TmrInterruptCreate(&OSTickTmrInterrupt); +} + + +/* +********************************************************************************************************* +********************************************************************************************************* +* LOCAL FUNCTIONS +********************************************************************************************************* +********************************************************************************************************* +*/ + +static void OSTimeTickHandler (void) +{ + OSIntEnter(); + OSTimeTick(); + CPU_ISR_End(); + OSIntExit(); +} + + +/* +********************************************************************************************************* +* OSTaskPosix() +* +* Description: This function is a generic POSIX task wrapper for uC/OS-III tasks. +* +* Arguments : p_arg Pointer to argument of the task's TCB. +* +* Note(s) : 1) Priorities of these tasks are very important. +********************************************************************************************************* +*/ + +static void *OSTaskPosix (void *p_arg) +{ + OS_TCB_EXT_POSIX *p_tcb_ext; + OS_TCB *p_tcb; + OS_ERR err; + + + p_tcb = (OS_TCB *)p_arg; + p_tcb_ext = (OS_TCB_EXT_POSIX *)p_tcb->ExtPtr; + + p_tcb_ext->ProcessId = syscall(SYS_gettid); + ERR_CHK(sem_post(&p_tcb_ext->InitSem)); + +#ifdef OS_CFG_MSG_TRACE_EN + if (p_tcb->NamePtr != (CPU_CHAR *)0) { + printf("Task[%3.1d] '%-32s' running\n", p_tcb->Prio, p_tcb->NamePtr); + } +#endif + + CPU_INT_DIS(); + { + int ret = -1u; + while (ret != 0u) { + ret = sem_wait(&p_tcb_ext->Sem); /* Wait until first CTX SW. */ + if ((ret != 0) && (ret != -EINTR)) { + ERR_CHK(ret); + } + } + } + CPU_INT_EN(); + + ((void (*)(void *))p_tcb->TaskEntryAddr)(p_tcb->TaskEntryArg); + + OSTaskDel(p_tcb, &err); /* Thread may exit at OSCtxSw(). */ + + return (0u); +} + + +/* +********************************************************************************************************* +* OSTaskTerminate() +* +* Description: This function handles task termination control signals. +* +* Arguments : p_task Pointer to the task information structure of the task to clear its control +* signals. +********************************************************************************************************* +*/ + +static void OSTaskTerminate (OS_TCB *p_tcb) +{ +#ifdef OS_CFG_MSG_TRACE_EN + if (p_tcb->NamePtr != (CPU_CHAR *)0) { + printf("Task[%3.1d] '%-32s' deleted\n", p_tcb->Prio, p_tcb->NamePtr); + } +#endif + + free(p_tcb->ExtPtr); +} + + +/* +********************************************************************************************************* +* OSThreadCreate() +* +* Description : Create new posix thread. +* +* Argument(s) : p_thread Pointer to preallocated thread variable. +* +* p_task Pointer to associated function. +* +* p_arg Pointer to associated function's argument. +* +* prio Thread priority. +* +* Return(s) : Thread's corresponding LWP pid. +* +* Note(s) : none. +* +********************************************************************************************************* +*/ + +static void OSThreadCreate (pthread_t *p_thread, + void *p_task, + void *p_arg, + int prio) +{ + pthread_attr_t attr; + struct sched_param param; + + + if (prio < sched_get_priority_min(SCHED_RR) || + prio > sched_get_priority_max(SCHED_RR)) { +#ifdef OS_CFG_MSG_TRACE_EN + printf("ThreadCreate(): Invalid prio arg.\n"); +#endif + raise(SIGABRT); + } + + ERR_CHK(pthread_attr_init(&attr)); + ERR_CHK(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)); + param.__sched_priority = prio; + ERR_CHK(pthread_attr_setschedpolicy(&attr, SCHED_RR)); + ERR_CHK(pthread_attr_setschedparam(&attr, ¶m)); + ERR_CHK(pthread_create(p_thread, &attr, p_task, p_arg)); +} + + +#ifdef __cplusplus +} +#endif diff --git a/rtos/uC-OS3/Source/__dbg_uCOS-III.c b/rtos/uC-OS3/Source/__dbg_uCOS-III.c new file mode 100644 index 00000000..facf23d2 --- /dev/null +++ b/rtos/uC-OS3/Source/__dbg_uCOS-III.c @@ -0,0 +1,32 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* VARIABLES +* +* File : __dbg_uCOS-III.C +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define OS_GLOBALS + +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *__dbg_uCOS_III__c = "$Id: $"; +#endif diff --git a/rtos/uC-OS3/Source/os.h b/rtos/uC-OS3/Source/os.h new file mode 100644 index 00000000..10a387d1 --- /dev/null +++ b/rtos/uC-OS3/Source/os.h @@ -0,0 +1,2436 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* File : os.h +* Version : V3.08.00 +********************************************************************************************************* +* Note(s) : (1) Assumes the following versions (or more recent) of software modules are included +* in the project build: +* +* (a) uC/CPU V1.31.00 +********************************************************************************************************* +*/ + +#ifndef OS_H +#define OS_H + +/* +************************************************************************************************************************ +* uC/OS-III VERSION NUMBER +************************************************************************************************************************ +*/ + +#define OS_VERSION 30800u /* Version of uC/OS-III (Vx.yy.zz mult. by 10000) */ + +/* +************************************************************************************************************************ +* INCLUDE HEADER FILES +************************************************************************************************************************ +*/ + +#include +#include +#include +#include "os_type.h" +#include +#include "os_trace.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* +************************************************************************************************************************ +* COMPATIBILITY CONFIGURATIONS +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_TASK_IDLE_EN +#define OS_CFG_TASK_IDLE_EN 1u +#endif + +#ifndef OS_CFG_TASK_STK_REDZONE_EN +#define OS_CFG_TASK_STK_REDZONE_EN 0u +#endif + +#ifndef OS_CFG_INVALID_OS_CALLS_CHK_EN +#define OS_CFG_INVALID_OS_CALLS_CHK_EN 0u +#endif + + +/* +************************************************************************************************************************ +* CRITICAL SECTION HANDLING +************************************************************************************************************************ +*/ + + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) && defined(CPU_CFG_INT_DIS_MEAS_EN) +#define OS_SCHED_LOCK_TIME_MEAS_START() OS_SchedLockTimeMeasStart() +#else +#define OS_SCHED_LOCK_TIME_MEAS_START() +#endif + + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) && defined(CPU_CFG_INT_DIS_MEAS_EN) +#define OS_SCHED_LOCK_TIME_MEAS_STOP() OS_SchedLockTimeMeasStop() +#else +#define OS_SCHED_LOCK_TIME_MEAS_STOP() +#endif + + +/* +************************************************************************************************************************ +* MISCELLANEOUS +************************************************************************************************************************ +*/ + +#ifdef OS_GLOBALS +#define OS_EXT +#else +#define OS_EXT extern +#endif + +#ifndef OS_FALSE +#define OS_FALSE 0u +#endif + +#ifndef OS_TRUE +#define OS_TRUE 1u +#endif + +#define OS_PRIO_TBL_SIZE (((OS_CFG_PRIO_MAX - 1u) / ((CPU_CFG_DATA_SIZE * 8u))) + 1u) + +#define OS_MSG_EN (((OS_CFG_TASK_Q_EN > 0u) || (OS_CFG_Q_EN > 0u)) ? 1u : 0u) + +#define OS_OBJ_TYPE_REQ (((OS_CFG_DBG_EN > 0u) || (OS_CFG_OBJ_TYPE_CHK_EN > 0u)) ? 1u : 0u) + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* # D E F I N E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +/* +======================================================================================================================== +* TASK STATUS +======================================================================================================================== +*/ + +#define OS_STATE_OS_STOPPED (OS_STATE)(0u) +#define OS_STATE_OS_RUNNING (OS_STATE)(1u) + +#define OS_STATE_NOT_RDY (CPU_BOOLEAN)(0u) +#define OS_STATE_RDY (CPU_BOOLEAN)(1u) + + + /* ------------------- TASK STATES ------------------ */ +#define OS_TASK_STATE_BIT_DLY (OS_STATE)(0x01u) /* /-------- SUSPENDED bit */ + /* | */ +#define OS_TASK_STATE_BIT_PEND (OS_STATE)(0x02u) /* | /----- PEND bit */ + /* | | */ +#define OS_TASK_STATE_BIT_SUSPENDED (OS_STATE)(0x04u) /* | | /--- Delayed/Timeout bit */ + /* | | | */ + /* V V V */ + +#define OS_TASK_STATE_RDY (OS_STATE)( 0u) /* 0 0 0 Ready */ +#define OS_TASK_STATE_DLY (OS_STATE)( 1u) /* 0 0 1 Delayed or Timeout */ +#define OS_TASK_STATE_PEND (OS_STATE)( 2u) /* 0 1 0 Pend */ +#define OS_TASK_STATE_PEND_TIMEOUT (OS_STATE)( 3u) /* 0 1 1 Pend + Timeout */ +#define OS_TASK_STATE_SUSPENDED (OS_STATE)( 4u) /* 1 0 0 Suspended */ +#define OS_TASK_STATE_DLY_SUSPENDED (OS_STATE)( 5u) /* 1 0 1 Suspended + Delayed or Timeout */ +#define OS_TASK_STATE_PEND_SUSPENDED (OS_STATE)( 6u) /* 1 1 0 Suspended + Pend */ +#define OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED (OS_STATE)( 7u) /* 1 1 1 Suspended + Pend + Timeout */ +#define OS_TASK_STATE_DEL (OS_STATE)(255u) + + /* ----------------- PENDING ON ... ----------------- */ +#define OS_TASK_PEND_ON_NOTHING (OS_STATE)( 0u) /* Pending on nothing */ +#define OS_TASK_PEND_ON_FLAG (OS_STATE)( 1u) /* Pending on event flag group */ +#define OS_TASK_PEND_ON_TASK_Q (OS_STATE)( 2u) /* Pending on message to be sent to task */ +#define OS_TASK_PEND_ON_COND (OS_STATE)( 3u) /* Pending on condition variable */ +#define OS_TASK_PEND_ON_MUTEX (OS_STATE)( 4u) /* Pending on mutual exclusion semaphore */ +#define OS_TASK_PEND_ON_Q (OS_STATE)( 5u) /* Pending on queue */ +#define OS_TASK_PEND_ON_SEM (OS_STATE)( 6u) /* Pending on semaphore */ +#define OS_TASK_PEND_ON_TASK_SEM (OS_STATE)( 7u) /* Pending on signal to be sent to task */ + +/* +------------------------------------------------------------------------------------------------------------------------ +* TASK PEND STATUS +* (Status codes for OS_TCBs field .PendStatus) +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_STATUS_PEND_OK (OS_STATUS)( 0u) /* Pending status OK, !pending, or pending complete */ +#define OS_STATUS_PEND_ABORT (OS_STATUS)( 1u) /* Pending aborted */ +#define OS_STATUS_PEND_DEL (OS_STATUS)( 2u) /* Pending object deleted */ +#define OS_STATUS_PEND_TIMEOUT (OS_STATUS)( 3u) /* Pending timed out */ + +/* +======================================================================================================================== +* OS OBJECT TYPES +* +* Note(s) : (1) OS_OBJ_TYPE_&&& #define values specifically chosen as ASCII representations of the kernel +* object types. Memory displays of kernel objects will display the kernel object TYPEs with +* their chosen ASCII names. +======================================================================================================================== +*/ + +#define OS_OBJ_TYPE_NONE (OS_OBJ_TYPE)CPU_TYPE_CREATE('N', 'O', 'N', 'E') +#define OS_OBJ_TYPE_FLAG (OS_OBJ_TYPE)CPU_TYPE_CREATE('F', 'L', 'A', 'G') +#define OS_OBJ_TYPE_MEM (OS_OBJ_TYPE)CPU_TYPE_CREATE('M', 'E', 'M', ' ') +#define OS_OBJ_TYPE_MUTEX (OS_OBJ_TYPE)CPU_TYPE_CREATE('M', 'U', 'T', 'X') +#define OS_OBJ_TYPE_COND (OS_OBJ_TYPE)CPU_TYPE_CREATE('C', 'O', 'N', 'D') +#define OS_OBJ_TYPE_Q (OS_OBJ_TYPE)CPU_TYPE_CREATE('Q', 'U', 'E', 'U') +#define OS_OBJ_TYPE_SEM (OS_OBJ_TYPE)CPU_TYPE_CREATE('S', 'E', 'M', 'A') +#define OS_OBJ_TYPE_TMR (OS_OBJ_TYPE)CPU_TYPE_CREATE('T', 'M', 'R', ' ') + +/* +======================================================================================================================== +* Possible values for 'opt' argument +======================================================================================================================== +*/ + +#define OS_OPT_NONE (OS_OPT)(0x0000u) + +/* +------------------------------------------------------------------------------------------------------------------------ +* DELETE OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_DEL_NO_PEND (OS_OPT)(0x0000u) +#define OS_OPT_DEL_ALWAYS (OS_OPT)(0x0001u) + +/* +------------------------------------------------------------------------------------------------------------------------ +* PEND OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_PEND_FLAG_MASK (OS_OPT)(0x000Fu) +#define OS_OPT_PEND_FLAG_CLR_ALL (OS_OPT)(0x0001u) /* Wait for ALL the bits specified to be CLR */ +#define OS_OPT_PEND_FLAG_CLR_AND (OS_OPT)(0x0001u) + +#define OS_OPT_PEND_FLAG_CLR_ANY (OS_OPT)(0x0002u) /* Wait for ANY of the bits specified to be CLR */ +#define OS_OPT_PEND_FLAG_CLR_OR (OS_OPT)(0x0002u) + +#define OS_OPT_PEND_FLAG_SET_ALL (OS_OPT)(0x0004u) /* Wait for ALL the bits specified to be SET */ +#define OS_OPT_PEND_FLAG_SET_AND (OS_OPT)(0x0004u) + +#define OS_OPT_PEND_FLAG_SET_ANY (OS_OPT)(0x0008u) /* Wait for ANY of the bits specified to be SET */ +#define OS_OPT_PEND_FLAG_SET_OR (OS_OPT)(0x0008u) + +#define OS_OPT_PEND_FLAG_CONSUME (OS_OPT)(0x0100u) /* Consume the flags if condition(s) satisfied */ + + +#define OS_OPT_PEND_BLOCKING (OS_OPT)(0x0000u) +#define OS_OPT_PEND_NON_BLOCKING (OS_OPT)(0x8000u) + +/* +------------------------------------------------------------------------------------------------------------------------ +* PEND ABORT OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_PEND_ABORT_1 (OS_OPT)(0x0000u) /* Pend abort a single waiting task */ +#define OS_OPT_PEND_ABORT_ALL (OS_OPT)(0x0100u) /* Pend abort ALL tasks waiting */ + +/* +------------------------------------------------------------------------------------------------------------------------ +* POST OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + + +#define OS_OPT_POST_NONE (OS_OPT)(0x0000u) + +#define OS_OPT_POST_FLAG_SET (OS_OPT)(0x0000u) +#define OS_OPT_POST_FLAG_CLR (OS_OPT)(0x0001u) + +#define OS_OPT_POST_FIFO (OS_OPT)(0x0000u) /* Default is to post FIFO */ +#define OS_OPT_POST_LIFO (OS_OPT)(0x0010u) /* Post to highest priority task waiting */ +#define OS_OPT_POST_1 (OS_OPT)(0x0000u) /* Post message to highest priority task waiting */ +#define OS_OPT_POST_ALL (OS_OPT)(0x0200u) /* Broadcast message to ALL tasks waiting */ + +#define OS_OPT_POST_NO_SCHED (OS_OPT)(0x8000u) /* Do not call the scheduler if this is selected */ + +/* +------------------------------------------------------------------------------------------------------------------------ +* TASK OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_TASK_NONE (OS_OPT)(0x0000u) /* No option selected */ +#define OS_OPT_TASK_STK_CHK (OS_OPT)(0x0001u) /* Enable stack checking for the task */ +#define OS_OPT_TASK_STK_CLR (OS_OPT)(0x0002u) /* Clear the stack when the task is create */ +#define OS_OPT_TASK_SAVE_FP (OS_OPT)(0x0004u) /* Save the contents of any floating-point registers */ +#define OS_OPT_TASK_NO_TLS (OS_OPT)(0x0008u) /* Specifies the task DOES NOT require TLS support */ + +/* +------------------------------------------------------------------------------------------------------------------------ +* TIME OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_TIME_DLY 0x00u +#define OS_OPT_TIME_TIMEOUT ((OS_OPT)0x02u) +#define OS_OPT_TIME_MATCH ((OS_OPT)0x04u) +#define OS_OPT_TIME_PERIODIC ((OS_OPT)0x08u) + +#define OS_OPT_TIME_HMSM_STRICT ((OS_OPT)0x00u) +#define OS_OPT_TIME_HMSM_NON_STRICT ((OS_OPT)0x10u) + +#define OS_OPT_TIME_MASK ((OS_OPT)(OS_OPT_TIME_DLY | \ + OS_OPT_TIME_TIMEOUT | \ + OS_OPT_TIME_PERIODIC | \ + OS_OPT_TIME_MATCH)) + +#define OS_OPT_TIME_OPTS_MASK ((OS_OPT)(OS_OPT_TIME_DLY | \ + OS_OPT_TIME_TIMEOUT | \ + OS_OPT_TIME_PERIODIC | \ + OS_OPT_TIME_MATCH | \ + OS_OPT_TIME_HMSM_NON_STRICT)) + +/* +------------------------------------------------------------------------------------------------------------------------ +* TIMER OPTIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_OPT_TMR_NONE (OS_OPT)(0u) /* No option selected */ + +#define OS_OPT_TMR_ONE_SHOT (OS_OPT)(1u) /* Timer will not auto restart when it expires */ +#define OS_OPT_TMR_PERIODIC (OS_OPT)(2u) /* Timer will auto restart when it expires */ + +#define OS_OPT_TMR_CALLBACK (OS_OPT)(3u) /* OSTmrStop() option to call 'callback' w/ timer arg */ +#define OS_OPT_TMR_CALLBACK_ARG (OS_OPT)(4u) /* OSTmrStop() option to call 'callback' w/ new arg */ + +/* +------------------------------------------------------------------------------------------------------------------------ +* TIMER STATES +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_TMR_STATE_UNUSED (OS_STATE)(0u) +#define OS_TMR_STATE_STOPPED (OS_STATE)(1u) +#define OS_TMR_STATE_RUNNING (OS_STATE)(2u) +#define OS_TMR_STATE_COMPLETED (OS_STATE)(3u) +#define OS_TMR_STATE_TIMEOUT (OS_STATE)(4u) + +/* +------------------------------------------------------------------------------------------------------------------------ +* PRIORITY +------------------------------------------------------------------------------------------------------------------------ +*/ + /* Dflt prio to init task TCB */ +#define OS_PRIO_INIT (OS_PRIO)(OS_CFG_PRIO_MAX) + +/* +------------------------------------------------------------------------------------------------------------------------ +* STACK REDZONE +------------------------------------------------------------------------------------------------------------------------ +*/ + +#define OS_STACK_CHECK_VAL 0x5432DCBAABCD2345UL +#define OS_STACK_CHECK_DEPTH 8u + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* E N U M E R A T I O N S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +/* +------------------------------------------------------------------------------------------------------------------------ +* ERROR CODES +------------------------------------------------------------------------------------------------------------------------ +*/ + +typedef enum os_err { + OS_ERR_NONE = 0u, + + OS_ERR_A = 10000u, + OS_ERR_ACCEPT_ISR = 10001u, + + OS_ERR_B = 11000u, + + OS_ERR_C = 12000u, + OS_ERR_CREATE_ISR = 12001u, + + OS_ERR_D = 13000u, + OS_ERR_DEL_ISR = 13001u, + + OS_ERR_E = 14000u, + + OS_ERR_F = 15000u, + OS_ERR_FATAL_RETURN = 15001u, + + OS_ERR_FLAG_GRP_DEPLETED = 15101u, + OS_ERR_FLAG_NOT_RDY = 15102u, + OS_ERR_FLAG_PEND_OPT = 15103u, + OS_ERR_FLUSH_ISR = 15104u, + + OS_ERR_G = 16000u, + + OS_ERR_H = 17000u, + + OS_ERR_I = 18000u, + OS_ERR_ILLEGAL_CREATE_RUN_TIME = 18001u, + + OS_ERR_ILLEGAL_DEL_RUN_TIME = 18007u, + + OS_ERR_J = 19000u, + + OS_ERR_K = 20000u, + + OS_ERR_L = 21000u, + OS_ERR_LOCK_NESTING_OVF = 21001u, + + OS_ERR_M = 22000u, + + OS_ERR_MEM_CREATE_ISR = 22201u, + OS_ERR_MEM_FULL = 22202u, + OS_ERR_MEM_INVALID_P_ADDR = 22203u, + OS_ERR_MEM_INVALID_BLKS = 22204u, + OS_ERR_MEM_INVALID_PART = 22205u, + OS_ERR_MEM_INVALID_P_BLK = 22206u, + OS_ERR_MEM_INVALID_P_MEM = 22207u, + OS_ERR_MEM_INVALID_P_DATA = 22208u, + OS_ERR_MEM_INVALID_SIZE = 22209u, + OS_ERR_MEM_NO_FREE_BLKS = 22210u, + + OS_ERR_MSG_POOL_EMPTY = 22301u, + OS_ERR_MSG_POOL_NULL_PTR = 22302u, + + OS_ERR_MUTEX_NOT_OWNER = 22401u, + OS_ERR_MUTEX_OWNER = 22402u, + OS_ERR_MUTEX_NESTING = 22403u, + OS_ERR_MUTEX_OVF = 22404u, + + OS_ERR_N = 23000u, + OS_ERR_NAME = 23001u, + OS_ERR_NO_MORE_ID_AVAIL = 23002u, + + OS_ERR_O = 24000u, + OS_ERR_OBJ_CREATED = 24001u, + OS_ERR_OBJ_DEL = 24002u, + OS_ERR_OBJ_PTR_NULL = 24003u, + OS_ERR_OBJ_TYPE = 24004u, + + OS_ERR_OPT_INVALID = 24101u, + + OS_ERR_OS_NOT_RUNNING = 24201u, + OS_ERR_OS_RUNNING = 24202u, + OS_ERR_OS_NOT_INIT = 24203u, + OS_ERR_OS_NO_APP_TASK = 24204u, + + OS_ERR_P = 25000u, + OS_ERR_PEND_ABORT = 25001u, + OS_ERR_PEND_ABORT_ISR = 25002u, + OS_ERR_PEND_ABORT_NONE = 25003u, + OS_ERR_PEND_ABORT_SELF = 25004u, + OS_ERR_PEND_DEL = 25005u, + OS_ERR_PEND_ISR = 25006u, + OS_ERR_PEND_LOCKED = 25007u, + OS_ERR_PEND_WOULD_BLOCK = 25008u, + + OS_ERR_POST_NULL_PTR = 25101u, + OS_ERR_POST_ISR = 25102u, + + OS_ERR_PRIO_EXIST = 25201u, + OS_ERR_PRIO = 25202u, + OS_ERR_PRIO_INVALID = 25203u, + + OS_ERR_PTR_INVALID = 25301u, + + OS_ERR_Q = 26000u, + OS_ERR_Q_FULL = 26001u, + OS_ERR_Q_EMPTY = 26002u, + OS_ERR_Q_MAX = 26003u, + OS_ERR_Q_SIZE = 26004u, + + OS_ERR_R = 27000u, + OS_ERR_REG_ID_INVALID = 27001u, + OS_ERR_ROUND_ROBIN_1 = 27002u, + OS_ERR_ROUND_ROBIN_DISABLED = 27003u, + + OS_ERR_S = 28000u, + OS_ERR_SCHED_INVALID_TIME_SLICE = 28001u, + OS_ERR_SCHED_LOCK_ISR = 28002u, + OS_ERR_SCHED_LOCKED = 28003u, + OS_ERR_SCHED_NOT_LOCKED = 28004u, + OS_ERR_SCHED_UNLOCK_ISR = 28005u, + + OS_ERR_SEM_OVF = 28101u, + OS_ERR_SET_ISR = 28102u, + + OS_ERR_STAT_RESET_ISR = 28201u, + OS_ERR_STAT_PRIO_INVALID = 28202u, + OS_ERR_STAT_STK_INVALID = 28203u, + OS_ERR_STAT_STK_SIZE_INVALID = 28204u, + OS_ERR_STATE_INVALID = 28205u, + OS_ERR_STATUS_INVALID = 28206u, + OS_ERR_STK_INVALID = 28207u, + OS_ERR_STK_SIZE_INVALID = 28208u, + OS_ERR_STK_LIMIT_INVALID = 28209u, + OS_ERR_STK_OVF = 28210u, + + OS_ERR_T = 29000u, + OS_ERR_TASK_CHANGE_PRIO_ISR = 29001u, + OS_ERR_TASK_CREATE_ISR = 29002u, + OS_ERR_TASK_DEL = 29003u, + OS_ERR_TASK_DEL_IDLE = 29004u, + OS_ERR_TASK_DEL_INVALID = 29005u, + OS_ERR_TASK_DEL_ISR = 29006u, + OS_ERR_TASK_INVALID = 29007u, + OS_ERR_TASK_NO_MORE_TCB = 29008u, + OS_ERR_TASK_NOT_DLY = 29009u, + OS_ERR_TASK_NOT_EXIST = 29010u, + OS_ERR_TASK_NOT_SUSPENDED = 29011u, + OS_ERR_TASK_OPT = 29012u, + OS_ERR_TASK_RESUME_ISR = 29013u, + OS_ERR_TASK_RESUME_PRIO = 29014u, + OS_ERR_TASK_RESUME_SELF = 29015u, + OS_ERR_TASK_RUNNING = 29016u, + OS_ERR_TASK_STK_CHK_ISR = 29017u, + OS_ERR_TASK_SUSPENDED = 29018u, + OS_ERR_TASK_SUSPEND_IDLE = 29019u, + OS_ERR_TASK_SUSPEND_INT_HANDLER = 29020u, + OS_ERR_TASK_SUSPEND_ISR = 29021u, + OS_ERR_TASK_SUSPEND_PRIO = 29022u, + OS_ERR_TASK_WAITING = 29023u, + OS_ERR_TASK_SUSPEND_CTR_OVF = 29024u, + + OS_ERR_TCB_INVALID = 29101u, + + OS_ERR_TLS_ID_INVALID = 29120u, + OS_ERR_TLS_ISR = 29121u, + OS_ERR_TLS_NO_MORE_AVAIL = 29122u, + OS_ERR_TLS_NOT_EN = 29123u, + OS_ERR_TLS_DESTRUCT_ASSIGNED = 29124u, + + OS_ERR_TICK_PRIO_INVALID = 29201u, + OS_ERR_TICK_STK_INVALID = 29202u, + OS_ERR_TICK_STK_SIZE_INVALID = 29203u, + OS_ERR_TICK_WHEEL_SIZE = 29204u, + OS_ERR_TICK_DISABLED = 29205u, + + OS_ERR_TIME_DLY_ISR = 29301u, + OS_ERR_TIME_DLY_RESUME_ISR = 29302u, + OS_ERR_TIME_GET_ISR = 29303u, + OS_ERR_TIME_INVALID_HOURS = 29304u, + OS_ERR_TIME_INVALID_MINUTES = 29305u, + OS_ERR_TIME_INVALID_SECONDS = 29306u, + OS_ERR_TIME_INVALID_MILLISECONDS = 29307u, + OS_ERR_TIME_NOT_DLY = 29308u, + OS_ERR_TIME_SET_ISR = 29309u, + OS_ERR_TIME_ZERO_DLY = 29310u, + + OS_ERR_TIMEOUT = 29401u, + + OS_ERR_TMR_INACTIVE = 29501u, + OS_ERR_TMR_INVALID_DEST = 29502u, + OS_ERR_TMR_INVALID_DLY = 29503u, + OS_ERR_TMR_INVALID_PERIOD = 29504u, + OS_ERR_TMR_INVALID_STATE = 29505u, + OS_ERR_TMR_INVALID = 29506u, + OS_ERR_TMR_ISR = 29507u, + OS_ERR_TMR_NO_CALLBACK = 29508u, + OS_ERR_TMR_NON_AVAIL = 29509u, + OS_ERR_TMR_PRIO_INVALID = 29510u, + OS_ERR_TMR_STK_INVALID = 29511u, + OS_ERR_TMR_STK_SIZE_INVALID = 29512u, + OS_ERR_TMR_STOPPED = 29513u, + OS_ERR_TMR_INVALID_CALLBACK = 29514u, + + OS_ERR_U = 30000u, + + OS_ERR_V = 31000u, + + OS_ERR_W = 32000u, + + OS_ERR_X = 33000u, + + OS_ERR_Y = 34000u, + OS_ERR_YIELD_ISR = 34001u, + + OS_ERR_Z = 35000u +} OS_ERR; + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* D A T A T Y P E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +typedef struct os_flag_grp OS_FLAG_GRP; + +typedef struct os_mem OS_MEM; + +typedef struct os_msg OS_MSG; +typedef struct os_msg_pool OS_MSG_POOL; +typedef struct os_msg_q OS_MSG_Q; + +typedef struct os_mutex OS_MUTEX; + +typedef struct os_cond OS_COND; + +typedef struct os_q OS_Q; + +typedef struct os_sem OS_SEM; + +typedef void (*OS_TASK_PTR)(void *p_arg); + +typedef struct os_tcb OS_TCB; + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) +typedef void *OS_TLS; + +typedef CPU_DATA OS_TLS_ID; + +typedef void (*OS_TLS_DESTRUCT_PTR)(OS_TCB *p_tcb, + OS_TLS_ID id, + OS_TLS value); +#endif + +typedef struct os_rdy_list OS_RDY_LIST; + +typedef struct os_tick_list OS_TICK_LIST; + +typedef void (*OS_TMR_CALLBACK_PTR)(void *p_tmr, void *p_arg); +typedef struct os_tmr OS_TMR; + +typedef struct os_pend_list OS_PEND_LIST; +typedef struct os_pend_obj OS_PEND_OBJ; + +#if (OS_CFG_APP_HOOKS_EN > 0u) +typedef void (*OS_APP_HOOK_VOID)(void); +typedef void (*OS_APP_HOOK_TCB)(OS_TCB *p_tcb); +#endif + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* D A T A S T R U C T U R E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +/* +------------------------------------------------------------------------------------------------------------------------ +* READY LIST +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_rdy_list { + OS_TCB *HeadPtr; /* Pointer to task that will run at selected priority */ + OS_TCB *TailPtr; /* Pointer to last task at selected priority */ +#if (OS_CFG_DBG_EN > 0u) + OS_OBJ_QTY NbrEntries; /* Number of entries at selected priority */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* PEND LIST +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_pend_list { + OS_TCB *HeadPtr; + OS_TCB *TailPtr; +#if (OS_CFG_DBG_EN > 0u) + OS_OBJ_QTY NbrEntries; +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* PEND OBJ +* +* Note(s) : (1) The 'os_pend_obj' structure data type is a template/subset for specific kernel objects' data types: +* 'os_flag_grp', 'os_mutex', 'os_q', and 'os_sem'. Each specific kernel object data type MUST define +* ALL generic OS pend object parameters, synchronized in both the sequential order & data type of each +* parameter. +* +* Thus, ANY modification to the sequential order or data types of OS pend object parameters MUST be +* appropriately synchronized between the generic OS pend object data type & ALL specific kernel objects' +* data types. +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_pend_obj { +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; +#endif + OS_PEND_LIST PendList; /* List of tasks pending on object */ +#if (OS_CFG_DBG_EN > 0u) + void *DbgPrevPtr; + void *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* EVENT FLAGS +* +* Note(s) : See PEND OBJ Note #1'. +------------------------------------------------------------------------------------------------------------------------ +*/ + + +struct os_flag_grp { /* Event Flag Group */ + /* ------------------ GENERIC MEMBERS ------------------ */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_FLAG */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to Event Flag Name (NUL terminated ASCII) */ +#endif + OS_PEND_LIST PendList; /* List of tasks waiting on event flag group */ +#if (OS_CFG_DBG_EN > 0u) + OS_FLAG_GRP *DbgPrevPtr; + OS_FLAG_GRP *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif + /* ------------------ SPECIFIC MEMBERS ------------------ */ + OS_FLAGS Flags; /* 8, 16 or 32 bit flags */ +#if (OS_CFG_TS_EN > 0u) + CPU_TS TS; /* Timestamp of when last post occurred */ +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U FlagID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* MEMORY PARTITIONS +------------------------------------------------------------------------------------------------------------------------ +*/ + + +struct os_mem { /* MEMORY CONTROL BLOCK */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_MEM */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; +#endif + void *AddrPtr; /* Pointer to beginning of memory partition */ + void *FreeListPtr; /* Pointer to list of free memory blocks */ + OS_MEM_SIZE BlkSize; /* Size (in bytes) of each block of memory */ + OS_MEM_QTY NbrMax; /* Total number of blocks in this partition */ + OS_MEM_QTY NbrFree; /* Number of memory blocks remaining in this partition */ +#if (OS_CFG_DBG_EN > 0u) + OS_MEM *DbgPrevPtr; + OS_MEM *DbgNextPtr; +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U MemID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* MESSAGES +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_msg { /* MESSAGE CONTROL BLOCK */ + OS_MSG *NextPtr; /* Pointer to next message */ + void *MsgPtr; /* Actual message */ + OS_MSG_SIZE MsgSize; /* Size of the message (in # bytes) */ +#if (OS_CFG_TS_EN > 0u) + CPU_TS MsgTS; /* Time stamp of when message was sent */ +#endif +}; + + + + +struct os_msg_pool { /* OS_MSG POOL */ + OS_MSG *NextPtr; /* Pointer to next message */ + OS_MSG_QTY NbrFree; /* Number of messages available from this pool */ + OS_MSG_QTY NbrUsed; /* Current number of messages used */ +#if (OS_CFG_DBG_EN > 0u) + OS_MSG_QTY NbrUsedMax; /* Peak number of messages used */ +#endif +}; + + + +struct os_msg_q { /* OS_MSG_Q */ + OS_MSG *InPtr; /* Pointer to next OS_MSG to be inserted in the queue */ + OS_MSG *OutPtr; /* Pointer to next OS_MSG to be extracted from the queue */ + OS_MSG_QTY NbrEntriesSize; /* Maximum allowable number of entries in the queue */ + OS_MSG_QTY NbrEntries; /* Current number of entries in the queue */ +#if (OS_CFG_DBG_EN > 0u) + OS_MSG_QTY NbrEntriesMax; /* Peak number of entries in the queue */ +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U MsgQID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* MUTUAL EXCLUSION SEMAPHORES +* +* Note(s) : See PEND OBJ Note #1'. +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_mutex { /* Mutual Exclusion Semaphore */ + /* ------------------ GENERIC MEMBERS ------------------ */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_MUTEX */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to Mutex Name (NUL terminated ASCII) */ +#endif + OS_PEND_LIST PendList; /* List of tasks waiting on mutex */ +#if (OS_CFG_DBG_EN > 0u) + OS_MUTEX *DbgPrevPtr; + OS_MUTEX *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif + /* ------------------ SPECIFIC MEMBERS ------------------ */ + OS_MUTEX *MutexGrpNextPtr; + OS_TCB *OwnerTCBPtr; + OS_NESTING_CTR OwnerNestingCtr; /* Mutex is available when the counter is 0 */ +#if (OS_CFG_TS_EN > 0u) + CPU_TS TS; +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U MutexID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* CONDITION VARIABLES +* +* Note(s) : See PEND OBJ Note #1'. +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_cond { /* Condition Variable */ + /* ------------------ GENERIC MEMBERS ------------------ */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_COND */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to Mutex Name (NUL terminated ASCII) */ +#endif + OS_PEND_LIST PendList; /* List of tasks waiting on condition variable */ +#if (OS_CFG_DBG_EN > 0u) + void *DbgPrevPtr; + void *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif + /* ------------------ SPECIFIC MEMBERS ------------------ */ + OS_MUTEX *Mutex; /* Mutex bound to the condition variable. */ +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* MESSAGE QUEUES +* +* Note(s) : See PEND OBJ Note #1'. +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_q { /* Message Queue */ + /* ------------------ GENERIC MEMBERS ------------------ */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_Q */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to Message Queue Name (NUL terminated ASCII) */ +#endif + OS_PEND_LIST PendList; /* List of tasks waiting on message queue */ +#if (OS_CFG_DBG_EN > 0u) + OS_Q *DbgPrevPtr; + OS_Q *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif + /* ------------------ SPECIFIC MEMBERS ------------------ */ + OS_MSG_Q MsgQ; /* List of messages */ +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* SEMAPHORES +* +* Note(s) : See PEND OBJ Note #1'. +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_sem { /* Semaphore */ + /* ------------------ GENERIC MEMBERS ------------------ */ +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_SEM */ +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to Semaphore Name (NUL terminated ASCII) */ +#endif + OS_PEND_LIST PendList; /* List of tasks waiting on semaphore */ +#if (OS_CFG_DBG_EN > 0u) + OS_SEM *DbgPrevPtr; + OS_SEM *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif + /* ------------------ SPECIFIC MEMBERS ------------------ */ + OS_SEM_CTR Ctr; +#if (OS_CFG_TS_EN > 0u) + CPU_TS TS; +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U SemID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* TASK CONTROL BLOCK +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_tcb { + CPU_STK *StkPtr; /* Pointer to current top of stack */ + + void *ExtPtr; /* Pointer to user definable data for TCB extension */ + + CPU_STK *StkLimitPtr; /* Pointer used to set stack 'watermark' limit */ + +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Pointer to task name */ +#endif + + OS_TCB *NextPtr; /* Pointer to next TCB in the TCB list */ + OS_TCB *PrevPtr; /* Pointer to previous TCB in the TCB list */ + +#if (OS_CFG_TICK_EN > 0u) + OS_TCB *TickNextPtr; + OS_TCB *TickPrevPtr; +#endif + +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) || (OS_CFG_TASK_STK_REDZONE_EN > 0u)) + CPU_STK *StkBasePtr; /* Pointer to base address of stack */ +#endif + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS TLS_Tbl[OS_CFG_TLS_TBL_SIZE]; +#endif + +#if (OS_CFG_DBG_EN > 0u) + OS_TASK_PTR TaskEntryAddr; /* Pointer to task entry point address */ + void *TaskEntryArg; /* Argument passed to task when it was created */ +#endif + + OS_TCB *PendNextPtr; /* Pointer to next TCB in pend list. */ + OS_TCB *PendPrevPtr; /* Pointer to previous TCB in pend list. */ + OS_PEND_OBJ *PendObjPtr; /* Pointer to object pended on. */ + OS_STATE PendOn; /* Indicates what task is pending on */ + OS_STATUS PendStatus; /* Pend status */ + + OS_STATE TaskState; /* See OS_TASK_STATE_xxx */ + OS_PRIO Prio; /* Task priority (0 == highest) */ +#if (OS_CFG_MUTEX_EN > 0u) + OS_PRIO BasePrio; /* Base priority (Not inherited) */ + OS_MUTEX *MutexGrpHeadPtr; /* Owned mutex group head pointer */ +#endif + +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) || (OS_CFG_TASK_STK_REDZONE_EN > 0u)) + CPU_STK_SIZE StkSize; /* Size of task stack (in number of stack elements) */ +#endif + OS_OPT Opt; /* Task options as passed by OSTaskCreate() */ + +#if (OS_CFG_TS_EN > 0u) + CPU_TS TS; /* Timestamp */ +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U SemID; /* Unique ID for third-party debuggers and tracers. */ +#endif + OS_SEM_CTR SemCtr; /* Task specific semaphore counter */ + + /* DELAY / TIMEOUT */ +#if (OS_CFG_TICK_EN > 0u) + OS_TICK TickRemain; /* Number of ticks remaining */ + OS_TICK TickCtrPrev; /* Used by OSTimeDlyXX() in PERIODIC mode */ +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + OS_TICK TimeQuanta; + OS_TICK TimeQuantaCtr; +#endif + +#if (OS_MSG_EN > 0u) + void *MsgPtr; /* Message received */ + OS_MSG_SIZE MsgSize; +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) + OS_MSG_Q MsgQ; /* Message queue associated with task */ +#if (OS_CFG_TASK_PROFILE_EN > 0u) + CPU_TS MsgQPendTime; /* Time it took for signal to be received */ + CPU_TS MsgQPendTimeMax; /* Max amount of time it took for signal to be received */ +#endif +#endif + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + OS_REG RegTbl[OS_CFG_TASK_REG_TBL_SIZE]; /* Task specific registers */ +#endif + +#if (OS_CFG_FLAG_EN > 0u) + OS_FLAGS FlagsPend; /* Event flag(s) to wait on */ + OS_FLAGS FlagsRdy; /* Event flags that made task ready to run */ + OS_OPT FlagsOpt; /* Options (See OS_OPT_FLAG_xxx) */ +#endif + +#if (OS_CFG_TASK_SUSPEND_EN > 0u) + OS_NESTING_CTR SuspendCtr; /* Nesting counter for OSTaskSuspend() */ +#endif + +#if (OS_CFG_TASK_PROFILE_EN > 0u) + OS_CPU_USAGE CPUUsage; /* CPU Usage of task (0.00-100.00%) */ + OS_CPU_USAGE CPUUsageMax; /* CPU Usage of task (0.00-100.00%) - Peak */ + OS_CTX_SW_CTR CtxSwCtr; /* Number of time the task was switched in */ + CPU_TS CyclesDelta; /* value of OS_TS_GET() - .CyclesStart */ + CPU_TS CyclesStart; /* Snapshot of cycle counter at start of task resumption */ + OS_CYCLES CyclesTotal; /* Total number of # of cycles the task has been running */ + OS_CYCLES CyclesTotalPrev; /* Snapshot of previous # of cycles */ + + CPU_TS SemPendTime; /* Time it took for signal to be received */ + CPU_TS SemPendTimeMax; /* Max amount of time it took for signal to be received */ +#endif + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) + CPU_STK_SIZE StkUsed; /* Number of stack elements used from the stack */ + CPU_STK_SIZE StkFree; /* Number of stack elements free on the stack */ +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + CPU_TS IntDisTimeMax; /* Maximum interrupt disable time */ +#endif +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + CPU_TS SchedLockTimeMax; /* Maximum scheduler lock time */ +#endif + +#if (OS_CFG_DBG_EN > 0u) + OS_TCB *DbgPrevPtr; + OS_TCB *DbgNextPtr; + CPU_CHAR *DbgNamePtr; +#endif +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) + CPU_INT16U TaskID; /* Unique ID for third-party debuggers and tracers. */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* TICK DATA TYPE +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_tick_list { + OS_TCB *TCB_Ptr; /* Pointer to list of tasks in tick list */ +#if (OS_CFG_DBG_EN > 0u) + OS_OBJ_QTY NbrEntries; /* Current number of entries in the tick list */ + OS_OBJ_QTY NbrUpdated; /* Number of entries updated */ +#endif +}; + + +/* +------------------------------------------------------------------------------------------------------------------------ +* TIMER DATA TYPES +------------------------------------------------------------------------------------------------------------------------ +*/ + +struct os_tmr { +#if (OS_OBJ_TYPE_REQ > 0u) + OS_OBJ_TYPE Type; +#endif +#if (OS_CFG_DBG_EN > 0u) + CPU_CHAR *NamePtr; /* Name to give the timer */ +#endif + OS_TMR_CALLBACK_PTR CallbackPtr; /* Function to call when timer expires */ + void *CallbackPtrArg; /* Argument to pass to function when timer expires */ + OS_TMR *NextPtr; /* Double link list pointers */ + OS_TMR *PrevPtr; + OS_TICK Remain; /* Amount of time remaining before timer expires */ + OS_TICK Dly; /* Delay before start of repeat */ + OS_TICK Period; /* Period to repeat timer */ + OS_OPT Opt; /* Options (see OS_OPT_TMR_xxx) */ + OS_STATE State; +#if (OS_CFG_DBG_EN > 0u) + OS_TMR *DbgPrevPtr; + OS_TMR *DbgNextPtr; +#endif +}; + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* G L O B A L V A R I A B L E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + /* APPLICATION HOOKS ------------------------ */ +#if (OS_CFG_APP_HOOKS_EN > 0u) +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +OS_EXT OS_APP_HOOK_TCB OS_AppRedzoneHitHookPtr; +#endif +OS_EXT OS_APP_HOOK_TCB OS_AppTaskCreateHookPtr; +OS_EXT OS_APP_HOOK_TCB OS_AppTaskDelHookPtr; +OS_EXT OS_APP_HOOK_TCB OS_AppTaskReturnHookPtr; + +OS_EXT OS_APP_HOOK_VOID OS_AppIdleTaskHookPtr; +OS_EXT OS_APP_HOOK_VOID OS_AppStatTaskHookPtr; +OS_EXT OS_APP_HOOK_VOID OS_AppTaskSwHookPtr; +OS_EXT OS_APP_HOOK_VOID OS_AppTimeTickHookPtr; +#endif + + /* IDLE TASK -------------------------------- */ +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_IDLE_CTR OSIdleTaskCtr; +#endif +#if (OS_CFG_TASK_IDLE_EN > 0u) +OS_EXT OS_TCB OSIdleTaskTCB; +#endif + + /* MISCELLANEOUS ---------------------------- */ +OS_EXT OS_NESTING_CTR OSIntNestingCtr; /* Interrupt nesting level */ +#ifdef CPU_CFG_INT_DIS_MEAS_EN +#if (OS_CFG_TS_EN > 0u) +OS_EXT CPU_TS OSIntDisTimeMax; /* Overall interrupt disable time */ +#endif +#endif + +OS_EXT OS_STATE OSRunning; /* Flag indicating the kernel is running */ +OS_EXT OS_STATE OSInitialized; /* Flag indicating the kernel is initialized */ + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) && (OS_CFG_ISR_STK_SIZE > 0u) +OS_EXT CPU_INT32U OSISRStkFree; /* Number of free ISR stack entries */ +OS_EXT CPU_INT32U OSISRStkUsed; /* Number of used ISR stack entries */ +#endif + + /* FLAGS ------------------------------------ */ +#if (OS_CFG_FLAG_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_FLAG_GRP *OSFlagDbgListPtr; +OS_EXT OS_OBJ_QTY OSFlagQty; +#endif +#endif + + /* MEMORY MANAGEMENT ------------------------ */ +#if (OS_CFG_MEM_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_MEM *OSMemDbgListPtr; +OS_EXT OS_OBJ_QTY OSMemQty; /* Number of memory partitions created */ +#endif +#endif + + /* OS_MSG POOL ------------------------------ */ +#if (OS_MSG_EN > 0u) +OS_EXT OS_MSG_POOL OSMsgPool; /* Pool of OS_MSG */ +#endif + + /* MUTEX MANAGEMENT ------------------------- */ +#if (OS_CFG_MUTEX_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_MUTEX *OSMutexDbgListPtr; +OS_EXT OS_OBJ_QTY OSMutexQty; /* Number of mutexes created */ +#endif +#endif + + /* PRIORITIES ------------------------------- */ +OS_EXT OS_PRIO OSPrioCur; /* Priority of current task */ +OS_EXT OS_PRIO OSPrioHighRdy; /* Priority of highest priority task */ +OS_EXT CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE]; + + /* QUEUES ----------------------------------- */ +#if (OS_CFG_Q_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_Q *OSQDbgListPtr; +OS_EXT OS_OBJ_QTY OSQQty; /* Number of message queues created */ +#endif +#endif + + + + /* READY LIST ------------------------------- */ +OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX]; /* Table of tasks ready to run */ + + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +OS_EXT CPU_BOOLEAN OSSafetyCriticalStartFlag; /* Flag indicating that all init. done */ +#endif + /* SCHEDULER -------------------------------- */ +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) +OS_EXT CPU_TS_TMR OSSchedLockTimeBegin; /* Scheduler lock time measurement */ +OS_EXT CPU_TS_TMR OSSchedLockTimeMax; +OS_EXT CPU_TS_TMR OSSchedLockTimeMaxCur; +#endif + +OS_EXT OS_NESTING_CTR OSSchedLockNestingCtr; /* Lock nesting level */ +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +OS_EXT OS_TICK OSSchedRoundRobinDfltTimeQuanta; +OS_EXT CPU_BOOLEAN OSSchedRoundRobinEn; /* Enable/Disable round-robin scheduling */ +#endif + /* SEMAPHORES ------------------------------- */ +#if (OS_CFG_SEM_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_SEM *OSSemDbgListPtr; +OS_EXT OS_OBJ_QTY OSSemQty; /* Number of semaphores created */ +#endif +#endif + + /* STATISTICS ------------------------------- */ +#if (OS_CFG_STAT_TASK_EN > 0u) +OS_EXT CPU_BOOLEAN OSStatResetFlag; /* Force the reset of the computed statistics */ +OS_EXT OS_CPU_USAGE OSStatTaskCPUUsage; /* CPU Usage in % */ +OS_EXT OS_CPU_USAGE OSStatTaskCPUUsageMax; /* CPU Usage in % (Peak) */ +OS_EXT OS_TICK OSStatTaskCtr; +OS_EXT OS_TICK OSStatTaskCtrMax; +OS_EXT OS_TICK OSStatTaskCtrRun; +OS_EXT CPU_BOOLEAN OSStatTaskRdy; +OS_EXT OS_TCB OSStatTaskTCB; +#if (OS_CFG_TS_EN > 0u) +OS_EXT CPU_TS OSStatTaskTime; +OS_EXT CPU_TS OSStatTaskTimeMax; +#endif +#endif + + /* TASKS ------------------------------------ */ +#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u)) +OS_EXT OS_CTX_SW_CTR OSTaskCtxSwCtr; /* Number of context switches */ +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_TCB *OSTaskDbgListPtr; +#endif +#endif + +OS_EXT OS_OBJ_QTY OSTaskQty; /* Number of tasks created */ + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) +OS_EXT OS_REG_ID OSTaskRegNextAvailID; /* Next available Task Register ID */ +#endif + + /* TICK ------------------------------------- */ +#if (OS_CFG_TICK_EN > 0u) +OS_EXT OS_TICK OSTickCtr; /* Cnts the #ticks since startup or last set */ +#if (OS_CFG_DYN_TICK_EN > 0u) +OS_EXT OS_TICK OSTickCtrStep; /* Number of ticks to the next tick task call.*/ +#endif +OS_EXT OS_TICK_LIST OSTickList; +#if (OS_CFG_TS_EN > 0u) +OS_EXT CPU_TS OSTickTime; +OS_EXT CPU_TS OSTickTimeMax; +#endif +#endif + + + +#if (OS_CFG_TMR_EN > 0u) /* TIMERS ----------------------------------- */ +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_TMR *OSTmrDbgListPtr; +OS_EXT OS_OBJ_QTY OSTmrListEntries; /* Doubly-linked list of timers */ +#endif +OS_EXT OS_TMR *OSTmrListPtr; +OS_EXT OS_COND OSTmrCond; +OS_EXT OS_MUTEX OSTmrMutex; + +#if (OS_CFG_DBG_EN > 0u) +OS_EXT OS_OBJ_QTY OSTmrQty; /* Number of timers created */ +#endif +OS_EXT OS_TCB OSTmrTaskTCB; /* TCB of timer task */ +#if (OS_CFG_TS_EN > 0u) +OS_EXT CPU_TS OSTmrTaskTime; +OS_EXT CPU_TS OSTmrTaskTimeMax; +#endif +OS_EXT OS_TICK OSTmrTaskTickBase; /* Tick to which timer delays are relative */ +OS_EXT OS_TICK OSTmrToTicksMult; /* Converts Timer time to Ticks Multiplier */ +#endif + + + + + /* TCBs ------------------------------------- */ +OS_EXT OS_TCB *OSTCBCurPtr; /* Pointer to currently running TCB */ +OS_EXT OS_TCB *OSTCBHighRdyPtr; /* Pointer to highest priority TCB */ + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* E X T E R N A L S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +extern CPU_STK * const OSCfg_IdleTaskStkBasePtr; +extern CPU_STK_SIZE const OSCfg_IdleTaskStkLimit; +extern CPU_STK_SIZE const OSCfg_IdleTaskStkSize; +extern CPU_INT32U const OSCfg_IdleTaskStkSizeRAM; + +extern CPU_STK * const OSCfg_ISRStkBasePtr; +extern CPU_STK_SIZE const OSCfg_ISRStkSize; +extern CPU_INT32U const OSCfg_ISRStkSizeRAM; + +extern OS_MSG_SIZE const OSCfg_MsgPoolSize; +extern CPU_INT32U const OSCfg_MsgPoolSizeRAM; +extern OS_MSG * const OSCfg_MsgPoolBasePtr; + +extern OS_PRIO const OSCfg_StatTaskPrio; +extern OS_RATE_HZ const OSCfg_StatTaskRate_Hz; +extern CPU_STK * const OSCfg_StatTaskStkBasePtr; +extern CPU_STK_SIZE const OSCfg_StatTaskStkLimit; +extern CPU_STK_SIZE const OSCfg_StatTaskStkSize; +extern CPU_INT32U const OSCfg_StatTaskStkSizeRAM; + +extern CPU_STK_SIZE const OSCfg_StkSizeMin; + +extern OS_RATE_HZ const OSCfg_TickRate_Hz; + +extern OS_PRIO const OSCfg_TmrTaskPrio; +extern OS_RATE_HZ const OSCfg_TmrTaskRate_Hz; +extern CPU_STK * const OSCfg_TmrTaskStkBasePtr; +extern CPU_STK_SIZE const OSCfg_TmrTaskStkLimit; +extern CPU_STK_SIZE const OSCfg_TmrTaskStkSize; +extern CPU_INT32U const OSCfg_TmrTaskStkSizeRAM; + +extern CPU_INT32U const OSCfg_DataSizeRAM; + +#if (OS_CFG_TASK_IDLE_EN > 0u) +extern CPU_STK OSCfg_IdleTaskStk[OS_CFG_IDLE_TASK_STK_SIZE]; +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0u) +extern CPU_STK OSCfg_ISRStk[OS_CFG_ISR_STK_SIZE]; +#endif + +#if (OS_MSG_EN > 0u) +extern OS_MSG OSCfg_MsgPool[OS_CFG_MSG_POOL_SIZE]; +#endif + +#if (OS_CFG_STAT_TASK_EN > 0u) +extern CPU_STK OSCfg_StatTaskStk[OS_CFG_STAT_TASK_STK_SIZE]; +#endif + +#if (OS_CFG_TMR_EN > 0u) +extern CPU_STK OSCfg_TmrTaskStk[OS_CFG_TMR_TASK_STK_SIZE]; +#endif + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* F U N C T I O N P R O T O T Y P E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +/* ================================================================================================================== */ +/* EVENT FLAGS */ +/* ================================================================================================================== */ + +#if (OS_CFG_FLAG_EN > 0u) + +void OSFlagCreate (OS_FLAG_GRP *p_grp, + CPU_CHAR *p_name, + OS_FLAGS flags, + OS_ERR *p_err); + +#if (OS_CFG_FLAG_DEL_EN > 0u) +OS_OBJ_QTY OSFlagDel (OS_FLAG_GRP *p_grp, + OS_OPT opt, + OS_ERR *p_err); +#endif + +OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err); + +#if (OS_CFG_FLAG_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSFlagPendAbort (OS_FLAG_GRP *p_grp, + OS_OPT opt, + OS_ERR *p_err); +#endif + +OS_FLAGS OSFlagPendGetFlagsRdy (OS_ERR *p_err); + +OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_OPT opt, + OS_ERR *p_err); + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_FlagClr (OS_FLAG_GRP *p_grp); + +void OS_FlagBlock (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_OPT opt, + OS_TICK timeout); + +#if (OS_CFG_DBG_EN > 0u) +void OS_FlagDbgListAdd (OS_FLAG_GRP *p_grp); + +void OS_FlagDbgListRemove (OS_FLAG_GRP *p_grp); +#endif + +void OS_FlagTaskRdy (OS_TCB *p_tcb, + OS_FLAGS flags_rdy, + CPU_TS ts); +#endif + + +/* ================================================================================================================== */ +/* FIXED SIZE MEMORY BLOCK MANAGEMENT */ +/* ================================================================================================================== */ + +#if (OS_CFG_MEM_EN > 0u) + +void OSMemCreate (OS_MEM *p_mem, + CPU_CHAR *p_name, + void *p_addr, + OS_MEM_QTY n_blks, + OS_MEM_SIZE blk_size, + OS_ERR *p_err); + +void *OSMemGet (OS_MEM *p_mem, + OS_ERR *p_err); + +void OSMemPut (OS_MEM *p_mem, + void *p_blk, + OS_ERR *p_err); + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +#if (OS_CFG_DBG_EN > 0u) +void OS_MemDbgListAdd (OS_MEM *p_mem); +#endif + +void OS_MemInit (OS_ERR *p_err); + +#endif + + +/* ================================================================================================================== */ +/* MUTUAL EXCLUSION SEMAPHORES */ +/* ================================================================================================================== */ + +#if (OS_CFG_MUTEX_EN > 0u) + +void OSMutexCreate (OS_MUTEX *p_mutex, + CPU_CHAR *p_name, + OS_ERR *p_err); + +#if (OS_CFG_MUTEX_DEL_EN > 0u) +OS_OBJ_QTY OSMutexDel (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err); +#endif + +void OSMutexPend (OS_MUTEX *p_mutex, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err); + +#if (OS_CFG_MUTEX_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSMutexPendAbort (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err); +#endif + +void OSMutexPost (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err); + + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_MutexClr (OS_MUTEX *p_mutex); + +#if (OS_CFG_DBG_EN > 0u) +void OS_MutexDbgListAdd (OS_MUTEX *p_mutex); + +void OS_MutexDbgListRemove (OS_MUTEX *p_mutex); +#endif + +void OS_MutexGrpAdd (OS_TCB *p_tcb, + OS_MUTEX *p_mutex); + +void OS_MutexGrpRemove (OS_TCB *p_tcb, + OS_MUTEX *p_mutex); + +OS_PRIO OS_MutexGrpPrioFindHighest(OS_TCB *p_tcb); + +void OS_MutexGrpPostAll (OS_TCB *p_tcb); +#endif + + +/* ================================================================================================================== */ +/* MESSAGE QUEUES */ +/* ================================================================================================================== */ + +#if (OS_CFG_Q_EN > 0u) + +void OSQCreate (OS_Q *p_q, + CPU_CHAR *p_name, + OS_MSG_QTY max_qty, + OS_ERR *p_err); + +#if (OS_CFG_Q_DEL_EN > 0u) +OS_OBJ_QTY OSQDel (OS_Q *p_q, + OS_OPT opt, + OS_ERR *p_err); +#endif + +#if (OS_CFG_Q_FLUSH_EN > 0u) +OS_MSG_QTY OSQFlush (OS_Q *p_q, + OS_ERR *p_err); +#endif + +void *OSQPend (OS_Q *p_q, + OS_TICK timeout, + OS_OPT opt, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err); + +#if (OS_CFG_Q_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSQPendAbort (OS_Q *p_q, + OS_OPT opt, + OS_ERR *p_err); +#endif + +void OSQPost (OS_Q *p_q, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + OS_ERR *p_err); + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_QClr (OS_Q *p_q); + +#if (OS_CFG_DBG_EN > 0u) +void OS_QDbgListAdd (OS_Q *p_q); + +void OS_QDbgListRemove (OS_Q *p_q); +#endif + +#endif + + +/* ================================================================================================================== */ +/* SEMAPHORES */ +/* ================================================================================================================== */ + +#if (OS_CFG_SEM_EN > 0u) + +void OSSemCreate (OS_SEM *p_sem, + CPU_CHAR *p_name, + OS_SEM_CTR cnt, + OS_ERR *p_err); + +#if (OS_CFG_SEM_DEL_EN > 0u) +OS_OBJ_QTY OSSemDel (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err); +#endif + +OS_SEM_CTR OSSemPend (OS_SEM *p_sem, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err); + +#if (OS_CFG_SEM_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSSemPendAbort (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err); +#endif + +OS_SEM_CTR OSSemPost (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err); + +#if (OS_CFG_SEM_SET_EN > 0u) +void OSSemSet (OS_SEM *p_sem, + OS_SEM_CTR cnt, + OS_ERR *p_err); +#endif + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_SemClr (OS_SEM *p_sem); + +#if (OS_CFG_DBG_EN > 0u) +void OS_SemDbgListAdd (OS_SEM *p_sem); + +void OS_SemDbgListRemove (OS_SEM *p_sem); +#endif + +#endif + + +/* ================================================================================================================== */ +/* TASK MANAGEMENT */ +/* ================================================================================================================== */ + +#if (OS_CFG_TASK_CHANGE_PRIO_EN > 0u) +void OSTaskChangePrio (OS_TCB *p_tcb, + OS_PRIO prio_new, + OS_ERR *p_err); +#endif + +void OSTaskCreate (OS_TCB *p_tcb, + CPU_CHAR *p_name, + OS_TASK_PTR p_task, + void *p_arg, + OS_PRIO prio, + CPU_STK *p_stk_base, + CPU_STK_SIZE stk_limit, + CPU_STK_SIZE stk_size, + OS_MSG_QTY q_size, + OS_TICK time_quanta, + void *p_ext, + OS_OPT opt, + OS_ERR *p_err); + +#if (OS_CFG_TASK_DEL_EN > 0u) +void OSTaskDel (OS_TCB *p_tcb, + OS_ERR *p_err); +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) +OS_MSG_QTY OSTaskQFlush (OS_TCB *p_tcb, + OS_ERR *p_err); + +void *OSTaskQPend (OS_TICK timeout, + OS_OPT opt, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err); + +CPU_BOOLEAN OSTaskQPendAbort (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err); + +void OSTaskQPost (OS_TCB *p_tcb, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + OS_ERR *p_err); + +#endif + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) +OS_REG OSTaskRegGet (OS_TCB *p_tcb, + OS_REG_ID id, + OS_ERR *p_err); + +OS_REG_ID OSTaskRegGetID (OS_ERR *p_err); + +void OSTaskRegSet (OS_TCB *p_tcb, + OS_REG_ID id, + OS_REG value, + OS_ERR *p_err); +#endif + +#if (OS_CFG_TASK_SUSPEND_EN > 0u) +void OSTaskResume (OS_TCB *p_tcb, + OS_ERR *p_err); + +void OSTaskSuspend (OS_TCB *p_tcb, + OS_ERR *p_err); +#endif + +OS_SEM_CTR OSTaskSemPend (OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err); + +#if (OS_CFG_TASK_SEM_PEND_ABORT_EN > 0u) +CPU_BOOLEAN OSTaskSemPendAbort (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err); +#endif + +OS_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err); + +OS_SEM_CTR OSTaskSemSet (OS_TCB *p_tcb, + OS_SEM_CTR cnt, + OS_ERR *p_err); + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) +void OSTaskStkChk (OS_TCB *p_tcb, + CPU_STK_SIZE *p_free, + CPU_STK_SIZE *p_used, + OS_ERR *p_err); +#endif + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +CPU_BOOLEAN OSTaskStkRedzoneChk (OS_TCB *p_tcb); +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +void OSSafetyCriticalStart (void); +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OSTaskTimeQuantaSet (OS_TCB *p_tcb, + OS_TICK time_quanta, + OS_ERR *p_err); +#endif + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_TaskBlock (OS_TCB *p_tcb, + OS_TICK timeout); + +#if (OS_CFG_DBG_EN > 0u) +void OS_TaskDbgListAdd (OS_TCB *p_tcb); + +void OS_TaskDbgListRemove (OS_TCB *p_tcb); +#endif + +void OS_TaskInit (OS_ERR *p_err); + +void OS_TaskInitTCB (OS_TCB *p_tcb); + +void OS_TaskReturn (void); + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +CPU_BOOLEAN OS_TaskStkRedzoneChk (CPU_STK *p_base, + CPU_STK_SIZE stk_size); + +void OS_TaskStkRedzoneInit (CPU_STK *p_base, + CPU_STK_SIZE stk_size); +#endif + +void OS_TaskChangePrio( OS_TCB *p_tcb, + OS_PRIO prio_new); + + +/* ================================================================================================================== */ +/* TIME MANAGEMENT */ +/* ================================================================================================================== */ + +void OSTimeDly (OS_TICK dly, + OS_OPT opt, + OS_ERR *p_err); + +#if (OS_CFG_TIME_DLY_HMSM_EN > 0u) +void OSTimeDlyHMSM (CPU_INT16U hours, + CPU_INT16U minutes, + CPU_INT16U seconds, + CPU_INT32U milli, + OS_OPT opt, + OS_ERR *p_err); +#endif + +#if (OS_CFG_TIME_DLY_RESUME_EN > 0u) +void OSTimeDlyResume (OS_TCB *p_tcb, + OS_ERR *p_err); +#endif + +OS_TICK OSTimeGet (OS_ERR *p_err); + +void OSTimeSet (OS_TICK ticks, + OS_ERR *p_err); + +void OSTimeTick (void); + +#if (OS_CFG_DYN_TICK_EN > 0u) +void OSTimeDynTick (OS_TICK ticks); +#endif + + +/* ================================================================================================================== */ +/* TIMER MANAGEMENT */ +/* ================================================================================================================== */ + +#if (OS_CFG_TMR_EN > 0u) +void OSTmrCreate (OS_TMR *p_tmr, + CPU_CHAR *p_name, + OS_TICK dly, + OS_TICK period, + OS_OPT opt, + OS_TMR_CALLBACK_PTR p_callback, + void *p_callback_arg, + OS_ERR *p_err); + +CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr, + OS_ERR *p_err); + +void OSTmrSet (OS_TMR *p_tmr, + OS_TICK dly, + OS_TICK period, + OS_TMR_CALLBACK_PTR p_callback, + void *p_callback_arg, + OS_ERR *p_err); + +OS_TICK OSTmrRemainGet (OS_TMR *p_tmr, + OS_ERR *p_err); + +CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr, + OS_ERR *p_err); + +OS_STATE OSTmrStateGet (OS_TMR *p_tmr, + OS_ERR *p_err); + +CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr, + OS_OPT opt, + void *p_callback_arg, + OS_ERR *p_err); + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_TmrClr (OS_TMR *p_tmr); + +#if (OS_CFG_DBG_EN > 0u) +void OS_TmrDbgListAdd (OS_TMR *p_tmr); + +void OS_TmrDbgListRemove (OS_TMR *p_tmr); +#endif + +void OS_TmrInit (OS_ERR *p_err); + +void OS_TmrLink (OS_TMR *p_tmr, + OS_TICK time); + +void OS_TmrUnlink (OS_TMR *p_tmr, + OS_TICK time); + +void OS_TmrTask (void *p_arg); + +#endif + + +/* ================================================================================================================== */ +/* TASK LOCAL STORAGE (TLS) SUPPORT */ +/* ================================================================================================================== */ + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) +OS_TLS_ID OS_TLS_GetID (OS_ERR *p_err); + +OS_TLS OS_TLS_GetValue (OS_TCB *p_tcb, + OS_TLS_ID id, + OS_ERR *p_err); + +void OS_TLS_Init (OS_ERR *p_err); + +void OS_TLS_SetValue (OS_TCB *p_tcb, + OS_TLS_ID id, + OS_TLS value, + OS_ERR *p_err); + +void OS_TLS_SetDestruct (OS_TLS_ID id, + OS_TLS_DESTRUCT_PTR p_destruct, + OS_ERR *p_err); + +void OS_TLS_TaskCreate (OS_TCB *p_tcb); + +void OS_TLS_TaskDel (OS_TCB *p_tcb); + +void OS_TLS_TaskSw (void); +#endif + + +/* ================================================================================================================== */ +/* MISCELLANEOUS */ +/* ================================================================================================================== */ + +void OSInit (OS_ERR *p_err); + +void OSIntEnter (void); +void OSIntExit (void); + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OSSchedRoundRobinCfg (CPU_BOOLEAN en, + OS_TICK dflt_time_quanta, + OS_ERR *p_err); + +void OSSchedRoundRobinYield (OS_ERR *p_err); + +#endif + +void OSSched (void); + +void OSSchedLock (OS_ERR *p_err); +void OSSchedUnlock (OS_ERR *p_err); + +void OSStart (OS_ERR *p_err); + +#if (OS_CFG_STAT_TASK_EN > 0u) +void OSStatReset (OS_ERR *p_err); + +void OSStatTaskCPUUsageInit (OS_ERR *p_err); +#endif + +CPU_INT16U OSVersion (OS_ERR *p_err); + +/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */ + +void OS_IdleTask (void *p_arg); + +void OS_IdleTaskInit (OS_ERR *p_err); + +#if (OS_CFG_STAT_TASK_EN > 0u) +void OS_StatTask (void *p_arg); +#endif + +void OS_StatTaskInit (OS_ERR *p_err); + +void OS_TickInit (OS_ERR *p_err); +void OS_TickUpdate (OS_TICK ticks); + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* T A R G E T S P E C I F I C F U N C T I O N S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +void OSIdleTaskHook (void); + +void OSInitHook (void); + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void OSRedzoneHitHook (OS_TCB *p_tcb); +#endif + +void OSStatTaskHook (void); + +void OSTaskCreateHook (OS_TCB *p_tcb); + +void OSTaskDelHook (OS_TCB *p_tcb); + +void OSTaskReturnHook (OS_TCB *p_tcb); + +CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, + void *p_arg, + CPU_STK *p_stk_base, + CPU_STK *p_stk_limit, + CPU_STK_SIZE stk_size, + OS_OPT opt); + +void OSTaskSwHook (void); + +void OSTimeTickHook (void); + + +/* +************************************************************************************************************************ +************************************************************************************************************************ +* u C / O S - I I I I N T E R N A L F U N C T I O N P R O T O T Y P E S +************************************************************************************************************************ +************************************************************************************************************************ +*/ + +void OSCfg_Init (void); + +#if (OS_CFG_DBG_EN > 0u) +void OS_Dbg_Init (void); +#endif + + +/* ----------------------------------------------- MESSAGE MANAGEMENT ----------------------------------------------- */ + +void OS_MsgPoolInit (OS_ERR *p_err); + +OS_MSG_QTY OS_MsgQFreeAll (OS_MSG_Q *p_msg_q); + +void *OS_MsgQGet (OS_MSG_Q *p_msg_q, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err); + +void OS_MsgQInit (OS_MSG_Q *p_msg_q, + OS_MSG_QTY size); + +void OS_MsgQPut (OS_MSG_Q *p_msg_q, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + CPU_TS ts, + OS_ERR *p_err); + +/* ---------------------------------------------- PEND/POST MANAGEMENT ---------------------------------------------- */ + +void OS_Pend (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb, + OS_STATE pending_on, + OS_TICK timeout); + +void OS_PendAbort (OS_TCB *p_tcb, + CPU_TS ts, + OS_STATUS reason); + +void OS_Post (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb, + void *p_void, + OS_MSG_SIZE msg_size, + CPU_TS ts); + +/* ----------------------------------------------- PRIORITY MANAGEMENT ---------------------------------------------- */ + +void OS_PrioInit (void); + +void OS_PrioInsert (OS_PRIO prio); + +void OS_PrioRemove (OS_PRIO prio); + +OS_PRIO OS_PrioGetHighest (void); + +/* --------------------------------------------------- SCHEDULING --------------------------------------------------- */ + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) +void OS_SchedLockTimeMeasStart (void); +void OS_SchedLockTimeMeasStop (void); +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list); +#endif + +/* --------------------------------------------- READY LIST MANAGEMENT ---------------------------------------------- */ + +void OS_RdyListInit (void); + +void OS_RdyListInsert (OS_TCB *p_tcb); + +void OS_RdyListInsertHead (OS_TCB *p_tcb); + +void OS_RdyListInsertTail (OS_TCB *p_tcb); + +void OS_RdyListMoveHeadToTail (OS_RDY_LIST *p_rdy_list); + +void OS_RdyListRemove (OS_TCB *p_tcb); + +/* ---------------------------------------------- PEND LIST MANAGEMENT ---------------------------------------------- */ + +#if (OS_CFG_DBG_EN > 0u) +void OS_PendDbgNameAdd (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb); + +void OS_PendDbgNameRemove (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb); +#endif + +void OS_PendListInit (OS_PEND_LIST *p_pend_list); + +void OS_PendListInsertPrio (OS_PEND_LIST *p_pend_list, + OS_TCB *p_tcb); + +void OS_PendListChangePrio (OS_TCB *p_tcb); + +void OS_PendListRemove (OS_TCB *p_tcb); + +/* ---------------------------------------------- TICK LIST MANAGEMENT ---------------------------------------------- */ +#if (OS_CFG_TICK_EN > 0u) +CPU_BOOLEAN OS_TickListInsert (OS_TCB *p_tcb, + OS_TICK elapsed, + OS_TICK tick_base, + OS_TICK time); + +void OS_TickListInsertDly (OS_TCB *p_tcb, + OS_TICK time, + OS_OPT opt, + OS_ERR *p_err); + +void OS_TickListRemove (OS_TCB *p_tcb); + +#if (OS_CFG_DYN_TICK_EN > 0u) /* OS_DynTick functions must be implemented in the BSP. */ +OS_TICK OS_DynTickGet (void); +OS_TICK OS_DynTickSet (OS_TICK ticks); +#endif +#endif + + +/* +************************************************************************************************************************ +* LOOK FOR MISSING #define CONSTANTS +* +* This section is used to generate ERROR messages at compile time if certain #define constants are +* MISSING in OS_CFG.H. This allows you to quickly determine the source of the error. +* +* You SHOULD NOT change this section UNLESS you would like to add more comments as to the source of the +* compile time error. +************************************************************************************************************************ +*/ + +/* +************************************************************************************************************************ +* MISCELLANEOUS +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_APP_HOOKS_EN +#error "OS_CFG.H, Missing OS_CFG_APP_HOOKS_EN: Enable (1) or Disable (0) application specific hook functions" +#endif + + +#ifndef OS_CFG_ARG_CHK_EN +#error "OS_CFG.H, Missing OS_CFG_ARG_CHK_EN: Enable (1) or Disable (0) argument checking" +#endif + + +#ifndef OS_CFG_DBG_EN +#error "OS_CFG.H, Missing OS_CFG_DBG_EN: Allows you to include variables for debugging or not" +#endif + + +#ifndef OS_CFG_CALLED_FROM_ISR_CHK_EN +#error "OS_CFG.H, Missing OS_CFG_CALLED_FROM_ISR_CHK_EN: Enable (1) or Disable (0) checking whether in an ISR in kernel services" +#endif + + +#ifndef OS_CFG_OBJ_TYPE_CHK_EN +#error "OS_CFG.H, Missing OS_CFG_OBJ_TYPE_CHK_EN: Enable (1) or Disable (0) checking for proper object types in kernel services" +#endif + + +#if OS_CFG_PRIO_MAX < 8u +#error "OS_CFG.H, OS_CFG_PRIO_MAX must be >= 8" +#endif + + +#ifndef OS_CFG_SCHED_LOCK_TIME_MEAS_EN +#error "OS_CFG.H, Missing OS_CFG_SCHED_LOCK_TIME_MEAS_EN: Include code to measure scheduler lock time" +#else + #if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) && \ + (OS_CFG_TS_EN == 0u) + #error "OS_CFG.H, OS_CFG_TS_EN must be Enabled (1) to measure scheduler lock time" + #endif +#endif + + +#ifndef OS_CFG_SCHED_ROUND_ROBIN_EN +#error "OS_CFG.H, Missing OS_CFG_SCHED_ROUND_ROBIN_EN: Include code for Round Robin Scheduling" +#else + #if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) && (OS_CFG_DYN_TICK_EN > 0u) + #error "OS_CFG.H, OS_CFG_DYN_TICK_EN must be Disabled (0) to use Round Robin scheduling." + #endif +#endif + + +#ifndef OS_CFG_STK_SIZE_MIN +#error "OS_CFG.H, Missing OS_CFG_STK_SIZE_MIN: Determines the minimum size for a task stack" +#endif + +#ifndef OS_CFG_TS_EN +#error "OS_CFG.H, Missing OS_CFG_TS_EN: Determines whether time stamping is enabled" +#else + #if (OS_CFG_TS_EN > 0u) && \ + (CPU_CFG_TS_EN == 0u) + #error "CPU_CFG.H, CPU_CFG_TS_32_EN must be Enabled (1) to use time stamp feature" + #endif +#endif + +/* +************************************************************************************************************************ +* EVENT FLAGS +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_FLAG_EN +#error "OS_CFG.H, Missing OS_CFG_FLAG_EN: Enable (1) or Disable (0) code generation for Event Flags" +#else + #ifndef OS_CFG_FLAG_DEL_EN + #error "OS_CFG.H, Missing OS_CFG_FLAG_DEL_EN: Include code for OSFlagDel()" + #endif + + #ifndef OS_CFG_FLAG_MODE_CLR_EN + #error "OS_CFG.H, Missing OS_CFG_FLAG_MODE_CLR_EN: Include code for Wait on Clear EVENT FLAGS" + #endif + + #ifndef OS_CFG_FLAG_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_CFG_FLAG_PEND_ABORT_EN: Include code for aborting pends from another task" + #endif +#endif + +/* +************************************************************************************************************************ +* MEMORY MANAGEMENT +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_MEM_EN +#error "OS_CFG.H, Missing OS_CFG_MEM_EN: Enable (1) or Disable (0) code generation for MEMORY MANAGER" +#endif + +/* +************************************************************************************************************************ +* MUTUAL EXCLUSION SEMAPHORES +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_MUTEX_EN +#error "OS_CFG.H, Missing OS_CFG_MUTEX_EN: Enable (1) or Disable (0) code generation for MUTEX" +#else + #ifndef OS_CFG_MUTEX_DEL_EN + #error "OS_CFG.H, Missing OS_CFG_MUTEX_DEL_EN: Include code for OSMutexDel()" + #endif + + #ifndef OS_CFG_MUTEX_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_CFG_MUTEX_PEND_ABORT_EN: Include code for OSMutexPendAbort()" + #endif +#endif + +/* +************************************************************************************************************************ +* MESSAGE QUEUES +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_Q_EN +#error "OS_CFG.H, Missing OS_CFG_Q_EN: Enable (1) or Disable (0) code generation for QUEUES" +#else + #ifndef OS_CFG_Q_DEL_EN + #error "OS_CFG.H, Missing OS_CFG_Q_DEL_EN: Include code for OSQDel()" + #endif + + #ifndef OS_CFG_Q_FLUSH_EN + #error "OS_CFG.H, Missing OS_CFG_Q_FLUSH_EN: Include code for OSQFlush()" + #endif + + #ifndef OS_CFG_Q_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_CFG_Q_PEND_ABORT_EN: Include code for OSQPendAbort()" + #endif +#endif + +/* +************************************************************************************************************************ +* SEMAPHORES +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_SEM_EN +#error "OS_CFG.H, Missing OS_CFG_SEM_EN: Enable (1) or Disable (0) code generation for SEMAPHORES" +#else + #ifndef OS_CFG_SEM_DEL_EN + #error "OS_CFG.H, Missing OS_CFG_SEM_DEL_EN: Include code for OSSemDel()" + #endif + + #ifndef OS_CFG_SEM_PEND_ABORT_EN + #error "OS_CFG.H, Missing OS_CFG_SEM_PEND_ABORT_EN: Include code for OSSemPendAbort()" + #endif + + #ifndef OS_CFG_SEM_SET_EN + #error "OS_CFG.H, Missing OS_CFG_SEM_SET_EN: Include code for OSSemSet()" + #endif +#endif + +/* +************************************************************************************************************************ +* TASK MANAGEMENT +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_STAT_TASK_EN +#error "OS_CFG.H, Missing OS_CFG_STAT_TASK_EN: Enable (1) or Disable(0) the statistics task" +#endif + +#ifndef OS_CFG_STAT_TASK_STK_CHK_EN +#error "OS_CFG.H, Missing OS_CFG_STAT_TASK_STK_CHK_EN: Check task stacks from statistics task" +#endif + +#ifndef OS_CFG_TASK_CHANGE_PRIO_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_CHANGE_PRIO_EN: Include code for OSTaskChangePrio()" +#endif + +#ifndef OS_CFG_TASK_DEL_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_DEL_EN: Include code for OSTaskDel()" +#endif + +#ifndef OS_CFG_TASK_Q_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_Q_EN: Include code for OSTaskQxxx()" +#endif + +#ifndef OS_CFG_TASK_Q_PEND_ABORT_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_Q_PEND_ABORT_EN: Include code for OSTaskQPendAbort()" +#endif + +#ifndef OS_CFG_TASK_PROFILE_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_PROFILE_EN: Include code for task profiling" +#else +#if (OS_CFG_TASK_PROFILE_EN > 0u) && \ + (OS_CFG_TASK_IDLE_EN == 0u) +#error "OS_CFG.H, OS_CFG_TASK_IDLE_EN must be Enabled (1) to use the task profiling feature" +#endif +#endif + +#ifndef OS_CFG_TASK_REG_TBL_SIZE +#error "OS_CFG.H, Missing OS_CFG_TASK_REG_TBL_SIZE: Include support for task specific registers" +#endif + +#ifndef OS_CFG_TASK_SEM_PEND_ABORT_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_SEM_PEND_ABORT_EN: Include code for OSTaskSemPendAbort()" +#endif + +#ifndef OS_CFG_TASK_SUSPEND_EN +#error "OS_CFG.H, Missing OS_CFG_TASK_SUSPEND_EN: Include code for OSTaskSuspend() and OSTaskResume()" +#endif + +/* +************************************************************************************************************************ +* TICK MANAGEMENT +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_TICK_EN +#error "OS_CFG.H, Missing OS_CFG_TICK_EN: Enable (1) or Disable (0) the kernel tick" +#else + #if ((OS_CFG_TICK_EN > 0u) && (OS_CFG_TICK_RATE_HZ == 0u)) + #error "OS_CFG_APP.h, OS_CFG_TICK_RATE_HZ must be > 0" + #endif + + #if ((OS_CFG_TICK_EN == 0u) && (OS_CFG_DYN_TICK_EN > 0u)) + #error "OS_CFG.H, OS_CFG_TICK_EN must be Enabled (1) to use the dynamic tick feature" + #endif +#endif + +/* +************************************************************************************************************************ +* TIME MANAGEMENT +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_TIME_DLY_HMSM_EN +#error "OS_CFG.H, Missing OS_CFG_TIME_DLY_HMSM_EN: Include code for OSTimeDlyHMSM()" +#endif + +#ifndef OS_CFG_TIME_DLY_RESUME_EN +#error "OS_CFG.H, Missing OS_CFG_TIME_DLY_RESUME_EN: Include code for OSTimeDlyResume()" +#endif + +/* +************************************************************************************************************************ +* TIMER MANAGEMENT +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_TMR_EN +#error "OS_CFG.H, Missing OS_CFG_TMR_EN: When (1) enables code generation for Timer Management" +#else +#if (OS_CFG_TMR_EN > 0u) + #if (OS_CFG_TICK_EN == 0u) + #error "OS_CFG.H, OS_CFG_TICK_EN must be Enabled (1) to use the timer feature" + #endif + + #if (OS_CFG_MUTEX_EN == 0u) + #error "OS_CFG.H, OS_CFG_MUTEX_EN must be Enabled (1) to use the timer feature" + #endif + + #if (OS_CFG_TMR_TASK_RATE_HZ == 0u) + #error "OS_CFG_APP.h, OS_CFG_TMR_TASK_RATE_HZ must be > 0" + #endif + + #if (OS_CFG_TICK_RATE_HZ < OS_CFG_TMR_TASK_RATE_HZ) + #error "OS_CFG_APP.h, OS_CFG_TICK_RATE_HZ must be >= OS_CFG_TMR_TASK_RATE_HZ" + #endif + + #ifndef OS_CFG_TMR_DEL_EN + #error "OS_CFG.H, Missing OS_CFG_TMR_DEL_EN: Enables (1) or Disables (0) code for OSTmrDel()" + #endif +#endif +#endif + +/* +************************************************************************************************************************ +* TRACE +************************************************************************************************************************ +*/ + +#ifndef OS_CFG_TRACE_EN +#error "OS_CFG.H, Missing OS_CFG_TRACE_EN: When (1) enables kernel events recording for Trace Analysis" +#else + #if (OS_CFG_TRACE_EN > 0u) && (OS_CFG_DBG_EN == 0u) + #error "OS_CFG.H, OS_CFG_DBG_EN must be enabled to use the trace feature" + #endif +#endif + +#ifndef OS_CFG_TRACE_API_ENTER_EN +#error "OS_CFG.H, Missing OS_CFG_TRACE_API_ENTER_EN: Enables (1) or Disables (0) the recording of the kernel API entry events for Trace Analysis" +#endif + +#ifndef OS_CFG_TRACE_API_EXIT_EN +#error "OS_CFG.H, Missing OS_CFG_TRACE_API_EXIT_EN: Enables (1) or Disables (0) the recording of the kernel API exit events for Trace Analysis" +#endif + +/* +************************************************************************************************************************ +* LIBRARY CONFIGURATION ERRORS +************************************************************************************************************************ +*/ + + /* See 'os.h Note #1a'. */ +#if CPU_CORE_VERSION < 13103u +#error "cpu_def.h, CPU_CORE_VERSION SHOULD be >= V1.31.03" +#endif + + +/* +************************************************************************************************************************ +* uC/OS-III MODULE END +************************************************************************************************************************ +*/ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/rtos/uC-OS3/Source/os_cfg_app.c b/rtos/uC-OS3/Source/os_cfg_app.c new file mode 100644 index 00000000..0a668479 --- /dev/null +++ b/rtos/uC-OS3/Source/os_cfg_app.c @@ -0,0 +1,253 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* OS CONFIGURATION (APPLICATION SPECIFICS) +* +* File : os_cfg_app.c +* Version : V3.08.00 +********************************************************************************************************* +* Note(s) : DO NOT CHANGE THIS FILE! +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_cfg_app__c = "$Id: $"; +#endif + +#if (OS_CFG_TASK_IDLE_EN > 0u) +#define OS_CFG_IDLE_TASK_STK_LIMIT ((OS_CFG_IDLE_TASK_STK_SIZE * OS_CFG_TASK_STK_LIMIT_PCT_EMPTY) / 100u) +#endif + +#if (OS_CFG_STAT_TASK_EN > 0u) +#define OS_CFG_STAT_TASK_STK_LIMIT ((OS_CFG_STAT_TASK_STK_SIZE * OS_CFG_TASK_STK_LIMIT_PCT_EMPTY) / 100u) +#endif + +#if (OS_CFG_TMR_EN > 0u) +#define OS_CFG_TMR_TASK_STK_LIMIT ((OS_CFG_TMR_TASK_STK_SIZE * OS_CFG_TASK_STK_LIMIT_PCT_EMPTY) / 100u) +#endif + +/* +************************************************************************************************************************ +* DATA STORAGE +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_IDLE_EN > 0u) +CPU_STK OSCfg_IdleTaskStk [OS_CFG_IDLE_TASK_STK_SIZE]; +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0u) +CPU_STK OSCfg_ISRStk [OS_CFG_ISR_STK_SIZE]; +#endif + +#if (OS_MSG_EN > 0u) +OS_MSG OSCfg_MsgPool [OS_CFG_MSG_POOL_SIZE]; +#endif + +#if (OS_CFG_STAT_TASK_EN > 0u) +CPU_STK OSCfg_StatTaskStk [OS_CFG_STAT_TASK_STK_SIZE]; +#endif + +#if (OS_CFG_TMR_EN > 0u) +CPU_STK OSCfg_TmrTaskStk [OS_CFG_TMR_TASK_STK_SIZE]; +#endif + +/* +************************************************************************************************************************ +* CONSTANTS +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_IDLE_EN > 0u) +CPU_STK * const OSCfg_IdleTaskStkBasePtr = &OSCfg_IdleTaskStk[0]; +CPU_STK_SIZE const OSCfg_IdleTaskStkLimit = OS_CFG_IDLE_TASK_STK_LIMIT; +CPU_STK_SIZE const OSCfg_IdleTaskStkSize = OS_CFG_IDLE_TASK_STK_SIZE; +CPU_INT32U const OSCfg_IdleTaskStkSizeRAM = sizeof(OSCfg_IdleTaskStk); +#else +CPU_STK * const OSCfg_IdleTaskStkBasePtr = (CPU_STK *)0; +CPU_STK_SIZE const OSCfg_IdleTaskStkLimit = 0u; +CPU_STK_SIZE const OSCfg_IdleTaskStkSize = 0u; +CPU_INT32U const OSCfg_IdleTaskStkSizeRAM = 0u; +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0u) +CPU_STK * const OSCfg_ISRStkBasePtr = &OSCfg_ISRStk[0]; +CPU_STK_SIZE const OSCfg_ISRStkSize = OS_CFG_ISR_STK_SIZE; +CPU_INT32U const OSCfg_ISRStkSizeRAM = sizeof(OSCfg_ISRStk); +#else +CPU_STK * const OSCfg_ISRStkBasePtr = (CPU_STK *)0; +CPU_STK_SIZE const OSCfg_ISRStkSize = 0u; +CPU_INT32U const OSCfg_ISRStkSizeRAM = 0u; +#endif + + +#if (OS_MSG_EN > 0u) +OS_MSG_SIZE const OSCfg_MsgPoolSize = OS_CFG_MSG_POOL_SIZE; +CPU_INT32U const OSCfg_MsgPoolSizeRAM = sizeof(OSCfg_MsgPool); +OS_MSG * const OSCfg_MsgPoolBasePtr = &OSCfg_MsgPool[0]; +#else +OS_MSG_SIZE const OSCfg_MsgPoolSize = 0u; +CPU_INT32U const OSCfg_MsgPoolSizeRAM = 0u; +OS_MSG * const OSCfg_MsgPoolBasePtr = (OS_MSG *)0; +#endif + + +#if (OS_CFG_STAT_TASK_EN > 0u) +OS_PRIO const OSCfg_StatTaskPrio = OS_CFG_STAT_TASK_PRIO; +OS_RATE_HZ const OSCfg_StatTaskRate_Hz = OS_CFG_STAT_TASK_RATE_HZ; +CPU_STK * const OSCfg_StatTaskStkBasePtr = &OSCfg_StatTaskStk[0]; +CPU_STK_SIZE const OSCfg_StatTaskStkLimit = OS_CFG_STAT_TASK_STK_LIMIT; +CPU_STK_SIZE const OSCfg_StatTaskStkSize = OS_CFG_STAT_TASK_STK_SIZE; +CPU_INT32U const OSCfg_StatTaskStkSizeRAM = sizeof(OSCfg_StatTaskStk); +#else +OS_PRIO const OSCfg_StatTaskPrio = 0u; +OS_RATE_HZ const OSCfg_StatTaskRate_Hz = 0u; +CPU_STK * const OSCfg_StatTaskStkBasePtr = (CPU_STK *)0; +CPU_STK_SIZE const OSCfg_StatTaskStkLimit = 0u; +CPU_STK_SIZE const OSCfg_StatTaskStkSize = 0u; +CPU_INT32U const OSCfg_StatTaskStkSizeRAM = 0u; +#endif + + +CPU_STK_SIZE const OSCfg_StkSizeMin = OS_CFG_STK_SIZE_MIN; + + +#if (OS_CFG_TICK_EN > 0u) +OS_RATE_HZ const OSCfg_TickRate_Hz = OS_CFG_TICK_RATE_HZ; +#else +OS_RATE_HZ const OSCfg_TickRate_Hz = 0u; +#endif + + +#if (OS_CFG_TMR_EN > 0u) +OS_PRIO const OSCfg_TmrTaskPrio = OS_CFG_TMR_TASK_PRIO; +OS_RATE_HZ const OSCfg_TmrTaskRate_Hz = OS_CFG_TMR_TASK_RATE_HZ; +CPU_STK * const OSCfg_TmrTaskStkBasePtr = &OSCfg_TmrTaskStk[0]; +CPU_STK_SIZE const OSCfg_TmrTaskStkLimit = OS_CFG_TMR_TASK_STK_LIMIT; +CPU_STK_SIZE const OSCfg_TmrTaskStkSize = OS_CFG_TMR_TASK_STK_SIZE; +CPU_INT32U const OSCfg_TmrTaskStkSizeRAM = sizeof(OSCfg_TmrTaskStk); +#else +OS_PRIO const OSCfg_TmrTaskPrio = 0u; +OS_RATE_HZ const OSCfg_TmrTaskRate_Hz = 0u; +CPU_STK * const OSCfg_TmrTaskStkBasePtr = (CPU_STK *)0; +CPU_STK_SIZE const OSCfg_TmrTaskStkLimit = 0u; +CPU_STK_SIZE const OSCfg_TmrTaskStkSize = 0u; +CPU_INT32U const OSCfg_TmrTaskStkSizeRAM = 0u; +#endif + + +/* +************************************************************************************************************************ +* TOTAL SIZE OF APPLICATION CONFIGURATION +************************************************************************************************************************ +*/ + +CPU_INT32U const OSCfg_DataSizeRAM = 0u + +#if (OS_CFG_TASK_IDLE_EN > 0u) + + sizeof(OSCfg_IdleTaskStk) +#endif + +#if (OS_MSG_EN > 0u) + + sizeof(OSCfg_MsgPool) +#endif + +#if (OS_CFG_STAT_TASK_EN > 0u) + + sizeof(OSCfg_StatTaskStk) +#endif + +#if (OS_CFG_TMR_EN > 0u) + + sizeof(OSCfg_TmrTaskStk) +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0u) + + sizeof(OSCfg_ISRStk) +#endif + + + 0u; + + + +/* +************************************************************************************************************************ +* OS CONFIGURATION INITIALIZATION +* +* Description: This function is used to make sure that debug variables that are unused in the application are not +* optimized away. This function might not be necessary for all compilers. In this case, you should simply +* DELETE the code in this function while still leaving the declaration of the function itself. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : (1) This code doesn't do anything, it simply prevents the compiler from optimizing out the 'const' +* variables which are declared in this file. +* (2) You may decide to 'compile out' the code (by using #if 0/#endif) INSIDE the function if your compiler +* DOES NOT optimize out the 'const' variables above. +************************************************************************************************************************ +*/ + +void OSCfg_Init (void) +{ + (void)OSCfg_DataSizeRAM; + +#if (OS_CFG_TASK_IDLE_EN > 0u) + (void)OSCfg_IdleTaskStkBasePtr; + (void)OSCfg_IdleTaskStkLimit; + (void)OSCfg_IdleTaskStkSize; + (void)OSCfg_IdleTaskStkSizeRAM; +#endif + + (void)OSCfg_ISRStkBasePtr; + (void)OSCfg_ISRStkSize; + (void)OSCfg_ISRStkSizeRAM; + +#if (OS_MSG_EN > 0u) + (void)OSCfg_MsgPoolSize; + (void)OSCfg_MsgPoolSizeRAM; + (void)OSCfg_MsgPoolBasePtr; +#endif + +#if (OS_CFG_STAT_TASK_EN > 0u) + (void)OSCfg_StatTaskPrio; + (void)OSCfg_StatTaskRate_Hz; + (void)OSCfg_StatTaskStkBasePtr; + (void)OSCfg_StatTaskStkLimit; + (void)OSCfg_StatTaskStkSize; + (void)OSCfg_StatTaskStkSizeRAM; +#endif + + (void)OSCfg_StkSizeMin; + +#if (OS_CFG_TICK_EN > 0u) + (void)OSCfg_TickRate_Hz; +#endif + +#if (OS_CFG_TMR_EN > 0u) + (void)OSCfg_TmrTaskPrio; + (void)OSCfg_TmrTaskRate_Hz; + (void)OSCfg_TmrTaskStkBasePtr; + (void)OSCfg_TmrTaskStkLimit; + (void)OSCfg_TmrTaskStkSize; + (void)OSCfg_TmrTaskStkSizeRAM; +#endif +} diff --git a/rtos/uC-OS3/Source/os_core.c b/rtos/uC-OS3/Source/os_core.c new file mode 100644 index 00000000..50a8a4f3 --- /dev/null +++ b/rtos/uC-OS3/Source/os_core.c @@ -0,0 +1,2163 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* CORE FUNCTIONS +* +* File : os_core.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_core__c = "$Id: $"; +#endif + +/* +************************************************************************************************************************ +* INITIALIZATION +* +* Description: This function is used to initialize the internals of uC/OS-III and MUST be called prior to +* creating any uC/OS-III object and, prior to calling OSStart(). +* +* Arguments : p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE Initialization was successful +* Other Other OS_ERR_xxx depending on the sub-functions called by OSInit(). +* Returns : none +************************************************************************************************************************ +*/ + +void OSInit (OS_ERR *p_err) +{ +#if (OS_CFG_ISR_STK_SIZE > 0u) + CPU_STK *p_stk; + CPU_STK_SIZE size; +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OSInitHook(); /* Call port specific initialization code */ + + OSIntNestingCtr = 0u; /* Clear the interrupt nesting counter */ + + OSRunning = OS_STATE_OS_STOPPED; /* Indicate that multitasking has not started */ + + OSSchedLockNestingCtr = 0u; /* Clear the scheduling lock counter */ + + OSTCBCurPtr = (OS_TCB *)0; /* Initialize OS_TCB pointers to a known state */ + OSTCBHighRdyPtr = (OS_TCB *)0; + + OSPrioCur = 0u; /* Initialize priority variables to a known state */ + OSPrioHighRdy = 0u; + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + OSSchedLockTimeBegin = 0u; + OSSchedLockTimeMax = 0u; + OSSchedLockTimeMaxCur = 0u; +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + OSSafetyCriticalStartFlag = OS_FALSE; +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + OSSchedRoundRobinEn = OS_FALSE; + OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u; +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0u) + p_stk = OSCfg_ISRStkBasePtr; /* Clear exception stack for stack checking. */ + if (p_stk != (CPU_STK *)0) { + size = OSCfg_ISRStkSize; + while (size > 0u) { + size--; + *p_stk = 0u; + p_stk++; + } + } +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) /* Initialize Redzoned ISR stack */ + OS_TaskStkRedzoneInit(OSCfg_ISRStkBasePtr, OSCfg_ISRStkSize); +#endif +#endif + +#if (OS_CFG_APP_HOOKS_EN > 0u) /* Clear application hook pointers */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + OS_AppRedzoneHitHookPtr = (OS_APP_HOOK_TCB )0; +#endif + OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0; + OS_AppTaskDelHookPtr = (OS_APP_HOOK_TCB )0; + OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0; + + OS_AppIdleTaskHookPtr = (OS_APP_HOOK_VOID)0; + OS_AppStatTaskHookPtr = (OS_APP_HOOK_VOID)0; + OS_AppTaskSwHookPtr = (OS_APP_HOOK_VOID)0; + OS_AppTimeTickHookPtr = (OS_APP_HOOK_VOID)0; +#endif + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + OSTaskRegNextAvailID = 0u; +#endif + + OS_PrioInit(); /* Initialize the priority bitmap table */ + + OS_RdyListInit(); /* Initialize the Ready List */ + + +#if (OS_CFG_FLAG_EN > 0u) /* Initialize the Event Flag module */ +#if (OS_CFG_DBG_EN > 0u) + OSFlagDbgListPtr = (OS_FLAG_GRP *)0; + OSFlagQty = 0u; +#endif +#endif + +#if (OS_CFG_MEM_EN > 0u) /* Initialize the Memory Manager module */ + OS_MemInit(p_err); + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_MSG_EN > 0u) /* Initialize the free list of OS_MSGs */ + OS_MsgPoolInit(p_err); + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_CFG_MUTEX_EN > 0u) /* Initialize the Mutex Manager module */ +#if (OS_CFG_DBG_EN > 0u) + OSMutexDbgListPtr = (OS_MUTEX *)0; + OSMutexQty = 0u; +#endif +#endif + + +#if (OS_CFG_Q_EN > 0u) /* Initialize the Message Queue Manager module */ +#if (OS_CFG_DBG_EN > 0u) + OSQDbgListPtr = (OS_Q *)0; + OSQQty = 0u; +#endif +#endif + + +#if (OS_CFG_SEM_EN > 0u) /* Initialize the Semaphore Manager module */ +#if (OS_CFG_DBG_EN > 0u) + OSSemDbgListPtr = (OS_SEM *)0; + OSSemQty = 0u; +#endif +#endif + + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_Init(p_err); /* Initialize Task Local Storage, before creating tasks */ + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + + OS_TaskInit(p_err); /* Initialize the task manager */ + if (*p_err != OS_ERR_NONE) { + return; + } + + +#if (OS_CFG_TASK_IDLE_EN > 0u) + OS_IdleTaskInit(p_err); /* Initialize the Idle Task */ + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_CFG_TICK_EN > 0u) + OS_TickInit(p_err); + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_CFG_STAT_TASK_EN > 0u) /* Initialize the Statistic Task */ + OS_StatTaskInit(p_err); + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_CFG_TMR_EN > 0u) /* Initialize the Timer Manager module */ + OS_TmrInit(p_err); + if (*p_err != OS_ERR_NONE) { + return; + } +#endif + + +#if (OS_CFG_DBG_EN > 0u) + OS_Dbg_Init(); +#endif + + + OSCfg_Init(); + + OSInitialized = OS_TRUE; /* Kernel is initialized */ +} + + +/* +************************************************************************************************************************ +* ENTER ISR +* +* Description: This function is used to notify uC/OS-III that you are about to service an interrupt service routine +* (ISR). This allows uC/OS-III to keep track of interrupt nesting and thus only perform rescheduling at +* the last nested ISR. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) This function MUST be called with interrupts already disabled +* +* 2) Your ISR can directly increment 'OSIntNestingCtr' without calling this function because OSIntNestingCtr has +* been declared 'global', the port is actually considered part of the OS and thus is allowed to access +* uC/OS-III variables. +* +* 3) You MUST still call OSIntExit() even though you increment 'OSIntNestingCtr' directly. +* +* 4) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call to OSIntEnter() +* (or direct increment to OSIntNestingCtr) at the beginning of the ISR you MUST have a call to OSIntExit() +* at the end of the ISR. +* +* 5) You are allowed to nest interrupts up to 250 levels deep. +************************************************************************************************************************ +*/ + +void OSIntEnter (void) +{ + OS_TRACE_ISR_ENTER(); + + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is OS running? */ + return; /* No */ + } + + if (OSIntNestingCtr >= 250u) { /* Have we nested past 250 levels? */ + return; /* Yes */ + } + + OSIntNestingCtr++; /* Increment ISR nesting level */ +} + + +/* +************************************************************************************************************************ +* EXIT ISR +* +* Description: This function is used to notify uC/OS-III that you have completed servicing an ISR. When the last nested +* ISR has completed, uC/OS-III will call the scheduler to determine whether a new, high-priority task, is +* ready to run. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call to OSIntEnter() +* (or direct increment to OSIntNestingCtr) at the beginning of the ISR you MUST have a call to OSIntExit() +* at the end of the ISR. +* +* 2) Rescheduling is prevented when the scheduler is locked (see OSSchedLock()) +************************************************************************************************************************ +*/ + +void OSIntExit (void) +{ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + CPU_BOOLEAN stk_status; +#endif + CPU_SR_ALLOC(); + + + + if (OSRunning != OS_STATE_OS_RUNNING) { /* Has the OS started? */ + OS_TRACE_ISR_EXIT(); + return; /* No */ + } + + CPU_INT_DIS(); + if (OSIntNestingCtr == 0u) { /* Prevent OSIntNestingCtr from wrapping */ + OS_TRACE_ISR_EXIT(); + CPU_INT_EN(); + return; + } + OSIntNestingCtr--; + if (OSIntNestingCtr > 0u) { /* ISRs still nested? */ + OS_TRACE_ISR_EXIT(); + CPU_INT_EN(); /* Yes */ + return; + } + + if (OSSchedLockNestingCtr > 0u) { /* Scheduler still locked? */ + OS_TRACE_ISR_EXIT(); + CPU_INT_EN(); /* Yes */ + return; + } + + /* Verify ISR Stack */ +#if (OS_CFG_ISR_STK_SIZE > 0u) +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + stk_status = OS_TaskStkRedzoneChk(OSCfg_ISRStkBasePtr, OSCfg_ISRStkSize); + if (stk_status != OS_TRUE) { + OSRedzoneHitHook((OS_TCB *)0); + } +#endif +#endif + + OSPrioHighRdy = OS_PrioGetHighest(); /* Find highest priority */ +#if (OS_CFG_TASK_IDLE_EN > 0u) + OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* Get highest priority task ready-to-run */ + if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ + /* Yes */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + stk_status = OSTaskStkRedzoneChk((OS_TCB *)0); + if (stk_status != OS_TRUE) { + OSRedzoneHitHook(OSTCBCurPtr); + } +#endif + OS_TRACE_ISR_EXIT(); + CPU_INT_EN(); + OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr); /* Do this here because we don't execute OSIntCtxSw(). */ + return; + } +#else + if (OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u)) { /* Are we returning to idle? */ + OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* No ... get highest priority task ready-to-run */ + if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ + /* Yes */ + OS_TRACE_ISR_EXIT(); + CPU_INT_EN(); + OS_TRACE_TASK_SWITCHED_IN(OSTCBHighRdyPtr); /* Do this here because we don't execute OSIntCtxSw(). */ + return; + } + } +#endif + +#if (OS_CFG_TASK_PROFILE_EN > 0u) + OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches for this new task */ +#endif +#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u)) + OSTaskCtxSwCtr++; /* Keep track of the total number of ctx switches */ +#endif + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_TaskSw(); +#endif + + OS_TRACE_ISR_EXIT_TO_SCHEDULER(); + + OSIntCtxSw(); /* Perform interrupt level ctx switch */ + + CPU_INT_EN(); +} + + +/* +************************************************************************************************************************ +* INDICATE THAT IT'S NO LONGER SAFE TO CREATE OBJECTS +* +* Description: This function is called by the application code to indicate that all initialization has been completed +* and that kernel objects are no longer allowed to be created. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#ifdef OS_SAFETY_CRITICAL_IEC61508 +void OSSafetyCriticalStart (void) +{ + OSSafetyCriticalStartFlag = OS_TRUE; +} + +#endif + + +/* +************************************************************************************************************************ +* SCHEDULER +* +* Description: This function is called by other uC/OS-III services to determine whether a new, high priority task has +* been made ready to run. This function is invoked by TASK level code and is not used to reschedule tasks +* from ISRs (see OSIntExit() for ISR rescheduling). +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) Rescheduling is prevented when the scheduler is locked (see OSSchedLock()) +************************************************************************************************************************ +*/ + +void OSSched (void) +{ + CPU_SR_ALLOC(); + + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) /* Can't schedule when the kernel is stopped. */ + if (OSRunning != OS_STATE_OS_RUNNING) { + return; + } +#endif + + if (OSIntNestingCtr > 0u) { /* ISRs still nested? */ + return; /* Yes ... only schedule when no nested ISRs */ + } + + if (OSSchedLockNestingCtr > 0u) { /* Scheduler locked? */ + return; /* Yes */ + } + + CPU_INT_DIS(); + OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority ready */ +#if (OS_CFG_TASK_IDLE_EN > 0u) + OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* Get highest priority task ready-to-run */ + if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ + CPU_INT_EN(); /* Yes */ + return; + } +#else + if (OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u)) { /* Are we returning to idle? */ + OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* No ... get highest priority task ready-to-run */ + if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */ + CPU_INT_EN(); /* Yes */ + return; + } + } +#endif + + OS_TRACE_TASK_PREEMPT(OSTCBCurPtr); + +#if (OS_CFG_TASK_PROFILE_EN > 0u) + OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches to this task */ +#endif + +#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u)) + OSTaskCtxSwCtr++; /* Increment context switch counter */ +#endif + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_TaskSw(); +#endif + +#if (OS_CFG_TASK_IDLE_EN > 0u) + OS_TASK_SW(); /* Perform a task level context switch */ + CPU_INT_EN(); +#else + if ((OSPrioHighRdy != (OS_CFG_PRIO_MAX - 1u))) { + OS_TASK_SW(); /* Perform a task level context switch */ + CPU_INT_EN(); + } else { + OSTCBHighRdyPtr = OSTCBCurPtr; + CPU_INT_EN(); + for (;;) { +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_EN > 0u)) + CPU_CRITICAL_ENTER(); +#if (OS_CFG_DBG_EN > 0u) + OSIdleTaskCtr++; +#endif +#if (OS_CFG_STAT_TASK_EN > 0u) + OSStatTaskCtr++; +#endif + CPU_CRITICAL_EXIT(); +#endif + +#if (OS_CFG_APP_HOOKS_EN > 0u) + OSIdleTaskHook(); /* Call user definable HOOK */ +#endif + if ((*((volatile OS_PRIO *)&OSPrioHighRdy) != (OS_CFG_PRIO_MAX - 1u))) { + break; + } + } + } +#endif + +#ifdef OS_TASK_SW_SYNC + OS_TASK_SW_SYNC(); +#endif +} + + +/* +************************************************************************************************************************ +* PREVENT SCHEDULING +* +* Description: This function is used to prevent rescheduling from taking place. This allows your application to prevent +* context switches until you are ready to permit context switching. +* +* Arguments : p_err is a pointer to a variable that will receive an error code: +* +* OS_ERR_NONE The scheduler is locked +* OS_ERR_LOCK_NESTING_OVF If you attempted to nest call to this function > 250 levels +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SCHED_LOCK_ISR If you called this function from an ISR +* +* Returns : none +* +* Note(s) : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every +* call to OSSchedLock() you MUST have a call to OSSchedUnlock(). +************************************************************************************************************************ +*/ + +void OSSchedLock (OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_SCHED_LOCK_ISR; + return; + } +#endif + + if (OSRunning != OS_STATE_OS_RUNNING) { /* Make sure multitasking is running */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } + + if (OSSchedLockNestingCtr >= 250u) { /* Prevent OSSchedLockNestingCtr overflowing */ + *p_err = OS_ERR_LOCK_NESTING_OVF; + return; + } + + CPU_CRITICAL_ENTER(); + OSSchedLockNestingCtr++; /* Increment lock nesting level */ +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + OS_SchedLockTimeMeasStart(); +#endif + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* ENABLE SCHEDULING +* +* Description: This function is used to re-allow rescheduling. +* +* Arguments : p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The scheduler has been enabled +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SCHED_LOCKED The scheduler is still locked, still nested +* OS_ERR_SCHED_NOT_LOCKED The scheduler was not locked +* OS_ERR_SCHED_UNLOCK_ISR If you called this function from an ISR +* +* Returns : none +* +* Note(s) : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every call to +* OSSchedLock() you MUST have a call to OSSchedUnlock(). +************************************************************************************************************************ +*/ + +void OSSchedUnlock (OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_SCHED_UNLOCK_ISR; + return; + } +#endif + + if (OSRunning != OS_STATE_OS_RUNNING) { /* Make sure multitasking is running */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } + + if (OSSchedLockNestingCtr == 0u) { /* See if the scheduler is locked */ + *p_err = OS_ERR_SCHED_NOT_LOCKED; + return; + } + + CPU_CRITICAL_ENTER(); + OSSchedLockNestingCtr--; /* Decrement lock nesting level */ + if (OSSchedLockNestingCtr > 0u) { + CPU_CRITICAL_EXIT(); /* Scheduler is still locked */ + *p_err = OS_ERR_SCHED_LOCKED; + return; + } + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + OS_SchedLockTimeMeasStop(); +#endif + + CPU_CRITICAL_EXIT(); /* Scheduler should be re-enabled */ + OSSched(); /* Run the scheduler */ + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* CONFIGURE ROUND-ROBIN SCHEDULING PARAMETERS +* +* Description: This function is called to change the round-robin scheduling parameters. +* +* Arguments : en determines whether round-robin will be enabled (when OS_TRUE) or not (when OS_FALSE) +* +* dflt_time_quanta default number of ticks between time slices. 0 means OSCfg_TickRate_Hz / 10. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OSSchedRoundRobinCfg (CPU_BOOLEAN en, + OS_TICK dflt_time_quanta, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (en == 0u) { + OSSchedRoundRobinEn = OS_FALSE; + } else { + OSSchedRoundRobinEn = OS_TRUE; + } + + if (dflt_time_quanta > 0u) { + OSSchedRoundRobinDfltTimeQuanta = dflt_time_quanta; + } else { + OSSchedRoundRobinDfltTimeQuanta = (OS_TICK)(OSCfg_TickRate_Hz / 10u); + } + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* YIELD CPU WHEN TASK NO LONGER NEEDS THE TIME SLICE +* +* Description: This function is called to give up the CPU when a task is done executing before its time slice expires. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful +* OS_ERR_ROUND_ROBIN_1 Only 1 task at this priority, nothing to yield to +* OS_ERR_ROUND_ROBIN_DISABLED Round Robin is not enabled +* OS_ERR_SCHED_LOCKED The scheduler has been locked +* OS_ERR_YIELD_ISR Can't be called from an ISR +* +* Returns : none +* +* Note(s) : 1) This function MUST be called from a task. +************************************************************************************************************************ +*/ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OSSchedRoundRobinYield (OS_ERR *p_err) +{ + OS_RDY_LIST *p_rdy_list; + OS_TCB *p_tcb; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't call this function from an ISR */ + *p_err = OS_ERR_YIELD_ISR; + return; + } +#endif + + if (OSSchedLockNestingCtr > 0u) { /* Can't yield if the scheduler is locked */ + *p_err = OS_ERR_SCHED_LOCKED; + return; + } + + if (OSSchedRoundRobinEn != OS_TRUE) { /* Make sure round-robin has been enabled */ + *p_err = OS_ERR_ROUND_ROBIN_DISABLED; + return; + } + + CPU_CRITICAL_ENTER(); + p_rdy_list = &OSRdyList[OSPrioCur]; /* Can't yield if it's the only task at that priority */ + if (p_rdy_list->HeadPtr == p_rdy_list->TailPtr) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_ROUND_ROBIN_1; + return; + } + + OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */ + p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */ + if (p_tcb->TimeQuanta == 0u) { /* See if we need to use the default time slice */ + p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; + } else { + p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */ + } + + CPU_CRITICAL_EXIT(); + + OSSched(); /* Run new task */ + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* START MULTITASKING +* +* Description: This function is used to start the multitasking process which lets uC/OS-III manage the task that you +* created. Before you can call OSStart(), you MUST have called OSInit() and you MUST have created at least +* one application task. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_FATAL_RETURN OS was running and OSStart() returned +* OS_ERR_OS_NOT_INIT OS is not initialized, OSStart() has no effect +* OS_ERR_OS_NO_APP_TASK No application task created, OSStart() has no effect +* OS_ERR_OS_RUNNING OS is already running, OSStart() has no effect +* +* Returns : none +* +* Note(s) : 1) OSStartHighRdy() MUST: +* a) Call OSTaskSwHook() then, +* b) Load the context of the task pointed to by OSTCBHighRdyPtr. +* c) Execute the task. +* +* 2) OSStart() is not supposed to return. If it does, that would be considered a fatal error. +************************************************************************************************************************ +*/ + +void OSStart (OS_ERR *p_err) +{ + OS_OBJ_QTY kernel_task_cnt; + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + if (OSInitialized != OS_TRUE) { + *p_err = OS_ERR_OS_NOT_INIT; + return; + } + + kernel_task_cnt = 0u; /* Calculate the number of kernel tasks */ +#if (OS_CFG_STAT_TASK_EN > 0u) + kernel_task_cnt++; +#endif +#if (OS_CFG_TMR_EN > 0u) + kernel_task_cnt++; +#endif +#if (OS_CFG_TASK_IDLE_EN > 0u) + kernel_task_cnt++; +#endif + + if (OSTaskQty <= kernel_task_cnt) { /* No application task created */ + *p_err = OS_ERR_OS_NO_APP_TASK; + return; + } + + if (OSRunning == OS_STATE_OS_STOPPED) { + OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority */ + OSPrioCur = OSPrioHighRdy; + OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; + OSTCBCurPtr = OSTCBHighRdyPtr; + OSRunning = OS_STATE_OS_RUNNING; + OSStartHighRdy(); /* Execute target specific code to start task */ + *p_err = OS_ERR_FATAL_RETURN; /* OSStart() is not supposed to return */ + } else { + *p_err = OS_ERR_OS_RUNNING; /* OS is already running */ + } +} + + +/* +************************************************************************************************************************ +* GET VERSION +* +* Description: This function is used to return the version number of uC/OS-III. The returned value corresponds to +* uC/OS-III's version number multiplied by 10000. In other words, version 3.01.02 would be returned as 30102. +* +* Arguments : p_err is a pointer to a variable that will receive an error code. However, OSVersion() set this +* variable to +* +* OS_ERR_NONE +* +* Returns : The version number of uC/OS-III multiplied by 10000. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +CPU_INT16U OSVersion (OS_ERR *p_err) +{ +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + *p_err = OS_ERR_NONE; + return (OS_VERSION); +} + + +/* +************************************************************************************************************************ +* IDLE TASK +* +* Description: This task is internal to uC/OS-III and executes whenever no other higher priority tasks executes because +* they are ALL waiting for event(s) to occur. +* +* Arguments : p_arg is an argument passed to the task when the task is created. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +* +* 2) OSIdleTaskHook() is called after the critical section to ensure that interrupts will be enabled for at +* least a few instructions. On some processors (ex. Philips XA), enabling and then disabling interrupts +* doesn't allow the processor enough time to have interrupts enabled before they were disabled again. +* uC/OS-III would thus never recognize interrupts. +* +* 3) This hook has been added to allow you to do such things as STOP the CPU to conserve power. +************************************************************************************************************************ +*/ +#if (OS_CFG_TASK_IDLE_EN > 0u) +void OS_IdleTask (void *p_arg) +{ +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_EN > 0u)) + CPU_SR_ALLOC(); +#endif + + + (void)p_arg; /* Prevent compiler warning for not using 'p_arg' */ + + for (;;) { +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_EN > 0u)) + CPU_CRITICAL_ENTER(); +#if (OS_CFG_DBG_EN > 0u) + OSIdleTaskCtr++; +#endif +#if (OS_CFG_STAT_TASK_EN > 0u) + OSStatTaskCtr++; +#endif + CPU_CRITICAL_EXIT(); +#endif + +#if (OS_CFG_APP_HOOKS_EN > 0u) + OSIdleTaskHook(); /* Call user definable HOOK */ +#endif + } +} +#endif + +/* +************************************************************************************************************************ +* INITIALIZE THE IDLE TASK +* +* Description: This function initializes the idle task +* +* Arguments : p_err is a pointer to a variable that will contain an error code returned by this function. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ +#if (OS_CFG_TASK_IDLE_EN > 0u) +void OS_IdleTaskInit (OS_ERR *p_err) +{ +#if (OS_CFG_DBG_EN > 0u) + OSIdleTaskCtr = 0u; +#endif + /* --------------- CREATE THE IDLE TASK --------------- */ + OSTaskCreate(&OSIdleTaskTCB, +#if (OS_CFG_DBG_EN == 0u) + (CPU_CHAR *)0, +#else + (CPU_CHAR *)"uC/OS-III Idle Task", +#endif + OS_IdleTask, + (void *)0, + (OS_PRIO )(OS_CFG_PRIO_MAX - 1u), + OSCfg_IdleTaskStkBasePtr, + OSCfg_IdleTaskStkLimit, + OSCfg_IdleTaskStkSize, + 0u, + 0u, + (void *)0, + (OS_OPT_TASK_STK_CHK | (OS_OPT)(OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS)), + p_err); +} +#endif + +/* +************************************************************************************************************************ +* BLOCK A TASK PENDING ON EVENT +* +* Description: This function is called to place a task in the blocked state waiting for an event to occur. This function +* exists because it is common to a number of OSxxxPend() services. +* +* Arguments : p_obj is a pointer to the object to pend on. If there are no object used to pend on then +* ----- the caller must pass a NULL pointer. +* +* p_tcb is the task that will be blocked. +* +* pending_on Specifies what the task will be pending on: +* +* OS_TASK_PEND_ON_FLAG +* OS_TASK_PEND_ON_TASK_Q <- No object (pending for a message sent to the task) +* OS_TASK_PEND_ON_MUTEX +* OS_TASK_PEND_ON_COND +* OS_TASK_PEND_ON_Q +* OS_TASK_PEND_ON_SEM +* OS_TASK_PEND_ON_TASK_SEM <- No object (pending on a signal sent to the task) +* +* timeout Is the amount of time the task will wait for the event to occur. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_Pend (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb, + OS_STATE pending_on, + OS_TICK timeout) +{ + OS_PEND_LIST *p_pend_list; + + + p_tcb->PendOn = pending_on; /* Resource not available, wait until it is */ + p_tcb->PendStatus = OS_STATUS_PEND_OK; + + OS_TaskBlock(p_tcb, /* Block the task and add it to the tick list if needed */ + timeout); + + if (p_obj != (OS_PEND_OBJ *)0) { /* Add the current task to the pend list ... */ + p_pend_list = &p_obj->PendList; /* ... if there is an object to pend on */ + p_tcb->PendObjPtr = p_obj; /* Save the pointer to the object pending on */ + OS_PendListInsertPrio(p_pend_list, /* Insert in the pend list in priority order */ + p_tcb); + + } else { + p_tcb->PendObjPtr = (OS_PEND_OBJ *)0; /* If no object being pended on, clear the pend object */ + } +#if (OS_CFG_DBG_EN > 0u) + OS_PendDbgNameAdd(p_obj, + p_tcb); +#endif +} + + +/* +************************************************************************************************************************ +* CANCEL PENDING +* +* Description: This function is called by the OSxxxPendAbort() and OSxxxDel() functions to cancel pending on an event. +* +* Arguments : p_tcb Is a pointer to the OS_TCB of the task that we'll abort the pend for +* ----- +* +* ts Is a timestamp as to when the pend was cancelled +* +* reason Indicates how the task was readied: +* +* OS_STATUS_PEND_DEL Object pended on was deleted. +* OS_STATUS_PEND_ABORT Pend was aborted. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_PendAbort (OS_TCB *p_tcb, + CPU_TS ts, + OS_STATUS reason) +{ +#if (OS_CFG_TS_EN == 0u) + (void)ts; /* Prevent compiler warning for not using 'ts' */ +#endif + + switch (p_tcb->TaskState) { + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = (void *)0; + p_tcb->MsgSize = 0u; +#endif +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + OS_PendListRemove(p_tcb); /* Remove task from the pend list */ + +#if (OS_CFG_TICK_EN > 0u) + if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) { + OS_TickListRemove(p_tcb); /* Cancel the timeout */ + } +#endif + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + p_tcb->TaskState = OS_TASK_STATE_RDY; /* Task will be ready */ + p_tcb->PendStatus = reason; /* Indicate how the task became ready */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ + break; + + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = (void *)0; + p_tcb->MsgSize = 0u; +#endif +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + OS_PendListRemove(p_tcb); /* Remove task from the pend list */ + +#if (OS_CFG_TICK_EN > 0u) + if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) { + OS_TickListRemove(p_tcb); /* Cancel the timeout */ + } +#endif + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; /* Task needs to remain suspended */ + p_tcb->PendStatus = reason; /* Indicate how the task became ready */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ + break; + + case OS_TASK_STATE_RDY: /* Cannot cancel a pend when a task is in these states. */ + case OS_TASK_STATE_DLY: + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_DLY_SUSPENDED: + default: + /* Default case. */ + break; + } +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE DEBUG NAMES TO PENDED OBJECT AND OS_TCB +* +* Description: These functions are used to add pointers to ASCII 'names' of objects so they can easily be displayed +* using a kernel aware tool. +* +* Arguments : p_obj is a pointer to the object being pended on +* +* p_tcb is a pointer to the OS_TCB of the task pending on the object +* +* Returns : none +* +* Note(s) : 1) These functions are INTERNAL to uC/OS-III and your application must not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_PendDbgNameAdd (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb1; + + + if (p_obj != (OS_PEND_OBJ *)0) { + p_tcb->DbgNamePtr = p_obj->NamePtr; /* Task pending on this object ... save name in TCB */ + p_pend_list = &p_obj->PendList; /* Find name of HP task pending on this object ... */ + p_tcb1 = p_pend_list->HeadPtr; + p_obj->DbgNamePtr = p_tcb1->NamePtr; /* ... Save in object */ + } else { + switch (p_tcb->PendOn) { + case OS_TASK_PEND_ON_TASK_Q: + p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Q"); + break; + + case OS_TASK_PEND_ON_TASK_SEM: + p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Sem"); + break; + + default: + p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" "); + break; + } + } +} + + +void OS_PendDbgNameRemove (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb1; + + + p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" "); /* Remove name of object pended on for readied task */ + + if (p_obj != (OS_PEND_OBJ *)0) { + p_pend_list = &p_obj->PendList; + p_tcb1 = p_pend_list->HeadPtr; + if (p_tcb1 != (OS_TCB *)0) { /* Find name of HP task pending on this object ... */ + p_obj->DbgNamePtr = p_tcb1->NamePtr; /* ... Save in object */ + } else { + p_obj->DbgNamePtr = (CPU_CHAR *)((void *)" "); /* Or no other task is pending on object */ + } + } +} +#endif + + +/* +************************************************************************************************************************ +* CHANGE THE PRIORITY OF A TASK WAITING IN A PEND LIST +* +* Description: This function is called to change the position of a task waiting in a pend list. The strategy used is to +* remove the task from the pend list and add it again using its changed priority. +* +* Arguments : p_tcb is a pointer to the TCB of the task to move +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +* +* 2) It's assumed that the TCB contains the NEW priority in its .Prio field. +************************************************************************************************************************ +*/ + +void OS_PendListChangePrio (OS_TCB *p_tcb) +{ + OS_PEND_LIST *p_pend_list; + OS_PEND_OBJ *p_obj; + + p_obj = p_tcb->PendObjPtr; /* Get pointer to pend list */ + p_pend_list = &p_obj->PendList; + + if (p_pend_list->HeadPtr->PendNextPtr != (OS_TCB *)0) { /* Only move if multiple entries in the list */ + OS_PendListRemove(p_tcb); /* Remove entry from current position */ + p_tcb->PendObjPtr = p_obj; + OS_PendListInsertPrio(p_pend_list, /* INSERT it back in the list */ + p_tcb); + } +} + + +/* +************************************************************************************************************************ +* INITIALIZE A WAIT LIST +* +* Description: This function is called to initialize the fields of an OS_PEND_LIST. +* +* Arguments : p_pend_list is a pointer to an OS_PEND_LIST +* ----------- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application must not call it. +************************************************************************************************************************ +*/ + +void OS_PendListInit (OS_PEND_LIST *p_pend_list) +{ + p_pend_list->HeadPtr = (OS_TCB *)0; + p_pend_list->TailPtr = (OS_TCB *)0; +#if (OS_CFG_DBG_EN > 0u) + p_pend_list->NbrEntries = 0u; +#endif +} + + +/* +************************************************************************************************************************ +* INSERT A TASK BASED ON IT'S PRIORITY IN A PEND LIST +* +* Description: This function is called to place an OS_TCB entry in a linked list based on its priority. The +* highest priority being placed at the head of the list. The TCB is assumed to contain the priority +* of the task in its .Prio field. +* +* CASE 0: Insert in an empty list. +* +* OS_PEND_LIST +* +---------------+ +* | TailPtr |-> 0 +* +---------------+ +* | HeadPtr |-> 0 +* +---------------+ +* | NbrEntries=0 | +* +---------------+ +* +* +* +* CASE 1: Insert BEFORE or AFTER an OS_TCB +* +* OS_PEND_LIST +* +--------------+ OS_TCB +* | TailPtr |--+---> +--------------+ +* +--------------+ | | PendNextPtr |->0 +* | HeadPtr |--/ +--------------+ +* +--------------+ 0<-| PendPrevPtr | +* | NbrEntries=1 | +--------------+ +* +--------------+ | | +* +--------------+ +* | | +* +--------------+ +* +* +* OS_PEND_LIST +* +--------------+ +* | TailPtr |---------------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +--------------+ +--------------+ +-> +--------------+ +* +--------------+ | PendNextPtr |<------| PendNextPtr | ...... | PendNextPtr |->0 +* | NbrEntries=N | +--------------+ +--------------+ +--------------+ +* +--------------+ 0<-| PendPrevPtr |<------| PendPrevPtr | ...... | PendPrevPtr | +* +--------------+ +--------------+ +--------------+ +* | | | | | | +* +--------------+ +--------------+ +--------------+ +* | | | | | | +* +--------------+ +--------------+ +--------------+ +* +* +* Arguments : p_pend_list is a pointer to the OS_PEND_LIST where the OS_TCB entry will be inserted +* ----------- +* +* p_tcb is the OS_TCB to insert in the list +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_PendListInsertPrio (OS_PEND_LIST *p_pend_list, + OS_TCB *p_tcb) +{ + OS_PRIO prio; + OS_TCB *p_tcb_next; + + + prio = p_tcb->Prio; /* Obtain the priority of the task to insert */ + + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* CASE 0: Insert when there are no entries */ +#if (OS_CFG_DBG_EN > 0u) + p_pend_list->NbrEntries = 1u; /* This is the first entry */ +#endif + p_tcb->PendNextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */ + p_tcb->PendPrevPtr = (OS_TCB *)0; + p_pend_list->HeadPtr = p_tcb; + p_pend_list->TailPtr = p_tcb; + } else { +#if (OS_CFG_DBG_EN > 0u) + p_pend_list->NbrEntries++; /* CASE 1: One more OS_TCBs in the list */ +#endif + p_tcb_next = p_pend_list->HeadPtr; + while (p_tcb_next != (OS_TCB *)0) { /* Find the position where to insert */ + if (prio < p_tcb_next->Prio) { + break; /* Found! ... insert BEFORE current */ + } else { + p_tcb_next = p_tcb_next->PendNextPtr; /* Not Found, follow the list */ + } + } + if (p_tcb_next == (OS_TCB *)0) { /* TCB to insert is lowest in priority */ + p_tcb->PendNextPtr = (OS_TCB *)0; /* ... insert at the tail. */ + p_tcb->PendPrevPtr = p_pend_list->TailPtr; + p_tcb->PendPrevPtr->PendNextPtr = p_tcb; + p_pend_list->TailPtr = p_tcb; + } else { + if (p_tcb_next->PendPrevPtr == (OS_TCB *)0) { /* Is new TCB highest priority? */ + p_tcb->PendNextPtr = p_tcb_next; /* Yes, insert as new Head of list */ + p_tcb->PendPrevPtr = (OS_TCB *)0; + p_tcb_next->PendPrevPtr = p_tcb; + p_pend_list->HeadPtr = p_tcb; + } else { /* No, insert in between two entries */ + p_tcb->PendNextPtr = p_tcb_next; + p_tcb->PendPrevPtr = p_tcb_next->PendPrevPtr; + p_tcb->PendPrevPtr->PendNextPtr = p_tcb; + p_tcb_next->PendPrevPtr = p_tcb; + } + } + } +} + + +/* +************************************************************************************************************************ +* REMOVE TASK FROM A PEND LIST KNOWING ONLY WHICH TCB TO REMOVE +* +* Description: This function is called to remove a task from a pend list knowing the TCB of the task to remove. +* +* CASE 0: OS_PEND_LIST list is empty, nothing to do. +* +* CASE 1: Only 1 OS_TCB in the list. +* +* OS_PEND_LIST +* +--------------+ OS_TCB +* | TailPtr |--+---> +--------------+ +* +--------------+ | | PendNextPtr |->0 +* | HeadPtr |--/ +--------------+ +* +--------------+ 0<-| PendPrevPtr | +* | NbrEntries=1 | +--------------+ +* +--------------+ | | +* +--------------+ +* | | +* +--------------+ +* +* CASE N: Two or more OS_TCBs in the list. +* +* OS_PEND_LIST +* +--------------+ +* | TailPtr |---------------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +--------------+ +--------------+ +-> +--------------+ +* +--------------+ | PendNextPtr |<------| PendNextPtr | ...... | PendNextPtr |->0 +* | NbrEntries=N | +--------------+ +--------------+ +--------------+ +* +--------------+ 0<-| PendPrevPtr |<------| PendPrevPtr | ...... | PendPrevPtr | +* +--------------+ +--------------+ +--------------+ +* | | | | | | +* +--------------+ +--------------+ +--------------+ +* | | | | | | +* +--------------+ +--------------+ +--------------+ +* +* +* Arguments : p_tcb is a pointer to the TCB of the task to remove from the pend list +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_PendListRemove (OS_TCB *p_tcb) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_next; + OS_TCB *p_prev; + + + if (p_tcb->PendObjPtr != (OS_PEND_OBJ *)0) { /* Only remove if object has a pend list. */ + p_pend_list = &p_tcb->PendObjPtr->PendList; /* Get pointer to pend list */ + + /* Remove TCB from the pend list. */ + if (p_pend_list->HeadPtr->PendNextPtr == (OS_TCB *)0) { + p_pend_list->HeadPtr = (OS_TCB *)0; /* Only one entry in the pend list */ + p_pend_list->TailPtr = (OS_TCB *)0; + } else if (p_tcb->PendPrevPtr == (OS_TCB *)0) { /* See if entry is at the head of the list */ + p_next = p_tcb->PendNextPtr; /* Yes */ + p_next->PendPrevPtr = (OS_TCB *)0; + p_pend_list->HeadPtr = p_next; + + } else if (p_tcb->PendNextPtr == (OS_TCB *)0) { /* See if entry is at the tail of the list */ + p_prev = p_tcb->PendPrevPtr; /* Yes */ + p_prev->PendNextPtr = (OS_TCB *)0; + p_pend_list->TailPtr = p_prev; + + } else { + p_prev = p_tcb->PendPrevPtr; /* Remove from inside the list */ + p_next = p_tcb->PendNextPtr; + p_prev->PendNextPtr = p_next; + p_next->PendPrevPtr = p_prev; + } +#if (OS_CFG_DBG_EN > 0u) + p_pend_list->NbrEntries--; /* One less entry in the list */ +#endif + p_tcb->PendNextPtr = (OS_TCB *)0; + p_tcb->PendPrevPtr = (OS_TCB *)0; + p_tcb->PendObjPtr = (OS_PEND_OBJ *)0; + } +} + + +/* +************************************************************************************************************************ +* POST TO A TASK +* +* Description: This function is called to post to a task. This function exist because it is common to a number of +* OSxxxPost() services. +* +* Arguments : p_obj Is a pointer to the object being posted to or NULL pointer if there is no object +* ----- +* +* p_tcb Is a pointer to the OS_TCB that will receive the 'post' +* ----- +* +* p_void If we are posting a message to a task, this is the message that the task will receive +* +* msg_size If we are posting a message to a task, this is the size of the message +* +* ts The timestamp as to when the post occurred +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_Post (OS_PEND_OBJ *p_obj, + OS_TCB *p_tcb, + void *p_void, + OS_MSG_SIZE msg_size, + CPU_TS ts) +{ +#if (OS_CFG_TS_EN == 0u) + (void)ts; /* Prevent compiler warning for not using 'ts' */ +#endif +#if (OS_MSG_EN == 0u) + (void)p_void; + (void)msg_size; +#endif + + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: /* Cannot Post a task that is ready */ + case OS_TASK_STATE_DLY: /* Cannot Post a task that is delayed */ + case OS_TASK_STATE_SUSPENDED: /* Cannot Post a suspended task */ + case OS_TASK_STATE_DLY_SUSPENDED: /* Cannot Post a suspended task that was also dly'd */ + break; + + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = p_void; /* Deposit message in OS_TCB of task waiting */ + p_tcb->MsgSize = msg_size; /* ... assuming posting a message */ +#endif +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + if (p_obj != (OS_PEND_OBJ *)0) { + OS_PendListRemove(p_tcb); /* Remove task from pend list */ + } +#if (OS_CFG_DBG_EN > 0u) + OS_PendDbgNameRemove(p_obj, + p_tcb); +#endif +#if (OS_CFG_TICK_EN > 0u) + if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) { + OS_TickListRemove(p_tcb); /* Remove from tick list */ + } +#endif + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + p_tcb->TaskState = OS_TASK_STATE_RDY; + p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ + break; + + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = p_void; /* Deposit message in OS_TCB of task waiting */ + p_tcb->MsgSize = msg_size; /* ... assuming posting a message */ +#endif +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + if (p_obj != (OS_PEND_OBJ *)0) { + OS_PendListRemove(p_tcb); /* Remove from pend list */ + } +#if (OS_CFG_DBG_EN > 0u) + OS_PendDbgNameRemove(p_obj, + p_tcb); +#endif +#if (OS_CFG_TICK_EN > 0u) + if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) { + OS_TickListRemove(p_tcb); /* Cancel any timeout */ + } +#endif + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; + p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ + break; + + default: + /* Default case. */ + break; + } +} + + +/* +************************************************************************************************************************ +* INITIALIZATION +* READY LIST INITIALIZATION +* +* Description: This function is called by OSInit() to initialize the ready list. The ready list contains a list of all +* the tasks that are ready to run. The list is actually an array of OS_RDY_LIST. An OS_RDY_LIST contains +* three fields. The number of OS_TCBs in the list (i.e. .NbrEntries), a pointer to the first OS_TCB in the +* OS_RDY_LIST (i.e. .HeadPtr) and a pointer to the last OS_TCB in the OS_RDY_LIST (i.e. .TailPtr). +* +* OS_TCBs are doubly linked in the OS_RDY_LIST and each OS_TCB points pack to the OS_RDY_LIST it belongs +* to. +* +* 'OS_RDY_LIST OSRdyTbl[OS_CFG_PRIO_MAX]' looks like this once initialized: +* +* +---------------+--------------+ +* | | TailPtr |-----> 0 +* [0] | NbrEntries=0 +--------------+ +* | | HeadPtr |-----> 0 +* +---------------+--------------+ +* | | TailPtr |-----> 0 +* [1] | NbrEntries=0 +--------------+ +* | | HeadPtr |-----> 0 +* +---------------+--------------+ +* : : +* : : +* : : +* +---------------+--------------+ +* | | TailPtr |-----> 0 +* [OS_CFG_PRIO_MAX-1] | NbrEntries=0 +--------------+ +* | | HeadPtr |-----> 0 +* +---------------+--------------+ +* +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_RdyListInit (void) +{ + CPU_INT32U i; + OS_RDY_LIST *p_rdy_list; + + + + for (i = 0u; i < OS_CFG_PRIO_MAX; i++) { /* Initialize the array of OS_RDY_LIST at each priority */ + p_rdy_list = &OSRdyList[i]; +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries = 0u; +#endif + p_rdy_list->HeadPtr = (OS_TCB *)0; + p_rdy_list->TailPtr = (OS_TCB *)0; + } +} + + +/* +************************************************************************************************************************ +* INSERT TCB IN THE READY LIST +* +* Description: This function is called to insert a TCB in the ready list. +* +* The TCB is inserted at the tail of the list if the priority of the TCB is the same as the priority of the +* current task. The TCB is inserted at the head of the list if not. +* +* Arguments : p_tcb is a pointer to the TCB to insert into the ready list +* ----- +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_RdyListInsert (OS_TCB *p_tcb) +{ + OS_PrioInsert(p_tcb->Prio); + if (p_tcb->Prio == OSPrioCur) { /* Are we readying a task at the same prio? */ + OS_RdyListInsertTail(p_tcb); /* Yes, insert readied task at the end of the list */ + } else { + OS_RdyListInsertHead(p_tcb); /* No, insert readied task at the beginning of the list*/ + } + + OS_TRACE_TASK_READY(p_tcb); +} + + +/* +************************************************************************************************************************ +* INSERT TCB AT THE BEGINNING OF A LIST +* +* Description: This function is called to place an OS_TCB at the beginning of a linked list as follows: +* +* CASE 0: Insert in an empty list. +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-> 0 +* +--------------+ +* | HeadPtr |-> 0 +* +--------------+ +* | NbrEntries=0 | +* +--------------+ +* +* +* +* CASE 1: Insert BEFORE the current head of list +* +* OS_RDY_LIST +* +--------------+ OS_TCB +* | TailPtr |--+---> +------------+ +* +--------------+ | | NextPtr |->0 +* | HeadPtr |--/ +------------+ +* +--------------+ 0<-| PrevPtr | +* | NbrEntries=1 | +------------+ +* +--------------+ : : +* : : +* +------------+ +* +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-----------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +------------+ +------------+ +-> +------------+ +* +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0 +* | NbrEntries=N | +------------+ +------------+ +------------+ +* +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr | +* +------------+ +------------+ +------------+ +* : : : : : : +* : : : : : : +* +------------+ +------------+ +------------+ +* +* +* Arguments : p_tcb is the OS_TCB to insert in the list +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_RdyListInsertHead (OS_TCB *p_tcb) +{ + OS_RDY_LIST *p_rdy_list; + OS_TCB *p_tcb2; + + + + p_rdy_list = &OSRdyList[p_tcb->Prio]; + if (p_rdy_list->HeadPtr == (OS_TCB *)0) { /* CASE 0: Insert when there are no entries */ +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries = 1u; /* This is the first entry */ +#endif + p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */ + p_tcb->PrevPtr = (OS_TCB *)0; + p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */ + p_rdy_list->TailPtr = p_tcb; + } else { /* CASE 1: Insert BEFORE the current head of list */ +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */ +#endif + p_tcb->NextPtr = p_rdy_list->HeadPtr; /* Adjust new OS_TCBs links */ + p_tcb->PrevPtr = (OS_TCB *)0; + p_tcb2 = p_rdy_list->HeadPtr; /* Adjust old head of list's links */ + p_tcb2->PrevPtr = p_tcb; + p_rdy_list->HeadPtr = p_tcb; + } +} + + +/* +************************************************************************************************************************ +* INSERT TCB AT THE END OF A LIST +* +* Description: This function is called to place an OS_TCB at the end of a linked list as follows: +* +* CASE 0: Insert in an empty list. +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-> 0 +* +--------------+ +* | HeadPtr |-> 0 +* +--------------+ +* | NbrEntries=0 | +* +--------------+ +* +* +* +* CASE 1: Insert AFTER the current tail of list +* +* OS_RDY_LIST +* +--------------+ OS_TCB +* | TailPtr |--+---> +------------+ +* +--------------+ | | NextPtr |->0 +* | HeadPtr |--/ +------------+ +* +--------------+ 0<-| PrevPtr | +* | NbrEntries=1 | +------------+ +* +--------------+ : : +* : : +* +------------+ +* +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-----------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +------------+ +------------+ +-> +------------+ +* +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0 +* | NbrEntries=N | +------------+ +------------+ +------------+ +* +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr | +* +------------+ +------------+ +------------+ +* : : : : : : +* : : : : : : +* +------------+ +------------+ +------------+ +* +* +* Arguments : p_tcb is the OS_TCB to insert in the list +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_RdyListInsertTail (OS_TCB *p_tcb) +{ + OS_RDY_LIST *p_rdy_list; + OS_TCB *p_tcb2; + + + + p_rdy_list = &OSRdyList[p_tcb->Prio]; + if (p_rdy_list->HeadPtr == (OS_TCB *)0) { /* CASE 0: Insert when there are no entries */ +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries = 1u; /* This is the first entry */ +#endif + p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */ + p_tcb->PrevPtr = (OS_TCB *)0; + p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */ + p_rdy_list->TailPtr = p_tcb; + } else { /* CASE 1: Insert AFTER the current tail of list */ +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */ +#endif + p_tcb->NextPtr = (OS_TCB *)0; /* Adjust new OS_TCBs links */ + p_tcb2 = p_rdy_list->TailPtr; + p_tcb->PrevPtr = p_tcb2; + p_tcb2->NextPtr = p_tcb; /* Adjust old tail of list's links */ + p_rdy_list->TailPtr = p_tcb; + } +} + + +/* +************************************************************************************************************************ +* MOVE TCB AT HEAD TO TAIL +* +* Description: This function is called to move the current head of a list to the tail of the list. +* +* +* CASE 0: TCB list is empty, nothing to do. +* +* CASE 1: Only 1 OS_TCB in the list, nothing to do. +* +* CASE 2: Only 2 OS_TCBs in the list. +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |--------------------------+ +* +--------------+ OS_TCB | OS_TCB +* | HeadPtr |------> +------------+ +-> +------------+ +* +--------------+ | NextPtr |------> | NextPtr |->0 +* | NbrEntries=2 | +------------+ +------------+ +* +--------------+ 0<-| PrevPtr | <------| PrevPtr | +* +------------+ +------------+ +* : : : : +* : : : : +* +------------+ +------------+ +* +* +* CASE N: More than 2 OS_TCBs in the list. +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-----------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +------------+ +------------+ +-> +------------+ +* +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0 +* | NbrEntries=N | +------------+ +------------+ +------------+ +* +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr | +* +------------+ +------------+ +------------+ +* : : : : : : +* : : : : : : +* +------------+ +------------+ +------------+ +* +* +* Arguments : p_rdy_list is a pointer to the OS_RDY_LIST where the OS_TCB will be inserted +* ------ +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_RdyListMoveHeadToTail (OS_RDY_LIST *p_rdy_list) +{ + OS_TCB *p_tcb1; + OS_TCB *p_tcb2; + OS_TCB *p_tcb3; + + + if (p_rdy_list->HeadPtr != p_rdy_list->TailPtr) { + if (p_rdy_list->HeadPtr->NextPtr == p_rdy_list->TailPtr) { /* SWAP the TCBs */ + p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */ + p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */ + p_tcb1->PrevPtr = p_tcb2; + p_tcb1->NextPtr = (OS_TCB *)0; + p_tcb2->PrevPtr = (OS_TCB *)0; + p_tcb2->NextPtr = p_tcb1; + p_rdy_list->HeadPtr = p_tcb2; + p_rdy_list->TailPtr = p_tcb1; + } else { + p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */ + p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */ + p_tcb3 = p_tcb1->NextPtr; /* Point to new list head */ + p_tcb3->PrevPtr = (OS_TCB *)0; /* Adjust back link of new list head */ + p_tcb1->NextPtr = (OS_TCB *)0; /* Adjust forward link of new list tail */ + p_tcb1->PrevPtr = p_tcb2; /* Adjust back link of new list tail */ + p_tcb2->NextPtr = p_tcb1; /* Adjust forward link of old list tail */ + p_rdy_list->HeadPtr = p_tcb3; /* Adjust new list head and tail pointers */ + p_rdy_list->TailPtr = p_tcb1; + } + } +} + + +/* +************************************************************************************************************************ +* REMOVE TCB FROM LIST KNOWING ONLY WHICH OS_TCB TO REMOVE +* +* Description: This function is called to remove an OS_TCB from an OS_RDY_LIST knowing the address of the OS_TCB to +* remove. +* +* +* CASE 0: TCB list is empty, nothing to do. +* +* CASE 1: Only 1 OS_TCBs in the list. +* +* OS_RDY_LIST +* +--------------+ OS_TCB +* | TailPtr |--+---> +------------+ +* +--------------+ | | NextPtr |->0 +* | HeadPtr |--/ +------------+ +* +--------------+ 0<-| PrevPtr | +* | NbrEntries=1 | +------------+ +* +--------------+ : : +* : : +* +------------+ +* +* CASE N: Two or more OS_TCBs in the list. +* +* OS_RDY_LIST +* +--------------+ +* | TailPtr |-----------------------------------------------+ +* +--------------+ OS_TCB OS_TCB | OS_TCB +* | HeadPtr |------> +------------+ +------------+ +-> +------------+ +* +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0 +* | NbrEntries=N | +------------+ +------------+ +------------+ +* +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr | +* +------------+ +------------+ +------------+ +* : : : : : : +* : : : : : : +* +------------+ +------------+ +------------+ +* +* +* Arguments : p_tcb is a pointer to the OS_TCB to remove +* ----- +* +* Returns : A pointer to the OS_RDY_LIST where the OS_TCB was +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_RdyListRemove (OS_TCB *p_tcb) +{ + OS_RDY_LIST *p_rdy_list; + OS_TCB *p_tcb1; + OS_TCB *p_tcb2; + + + + p_rdy_list = &OSRdyList[p_tcb->Prio]; + p_tcb1 = p_tcb->PrevPtr; /* Point to next and previous OS_TCB in the list */ + p_tcb2 = p_tcb->NextPtr; + if (p_tcb1 == (OS_TCB *)0) { /* Was the OS_TCB to remove at the head? */ + if (p_tcb2 == (OS_TCB *)0) { /* Yes, was it the only OS_TCB? */ +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries = 0u; /* Yes, no more entries */ +#endif + p_rdy_list->HeadPtr = (OS_TCB *)0; + p_rdy_list->TailPtr = (OS_TCB *)0; + OS_PrioRemove(p_tcb->Prio); + } else { +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries--; /* No, one less entry */ +#endif + p_tcb2->PrevPtr = (OS_TCB *)0; /* adjust back link of new list head */ + p_rdy_list->HeadPtr = p_tcb2; /* adjust OS_RDY_LIST's new head */ + } + } else { +#if (OS_CFG_DBG_EN > 0u) + p_rdy_list->NbrEntries--; /* No, one less entry */ +#endif + p_tcb1->NextPtr = p_tcb2; + if (p_tcb2 == (OS_TCB *)0) { + p_rdy_list->TailPtr = p_tcb1; /* Removing the TCB at the tail, adj the tail ptr */ + } else { + p_tcb2->PrevPtr = p_tcb1; + } + } + p_tcb->PrevPtr = (OS_TCB *)0; + p_tcb->NextPtr = (OS_TCB *)0; + + OS_TRACE_TASK_SUSPENDED(p_tcb); +} + + +/* +************************************************************************************************************************ +* SCHEDULER LOCK TIME MEASUREMENT +* +* Description: These functions are used to measure the peak amount of time that the scheduler is locked +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) The are internal functions to uC/OS-III and MUST not be called by your application code. +* +* 2) It's assumed that these functions are called when interrupts are disabled. +* +* 3) We are reading the time stamp timer via OS_TS_GET() directly even if this is a 16-bit timer. The +* reason is that we don't expect to have the scheduler locked for 65536 counts even at the rate the TS +* timer is updated. In other words, locking the scheduler for longer than 65536 count would not be a +* good thing for a real-time system. +************************************************************************************************************************ +*/ + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) +void OS_SchedLockTimeMeasStart (void) +{ + if (OSSchedLockNestingCtr == 1u) { + OSSchedLockTimeBegin = OS_TS_GET(); + } +} + + + + +void OS_SchedLockTimeMeasStop (void) +{ + CPU_TS_TMR delta; + + + if (OSSchedLockNestingCtr == 0u) { /* Make sure we fully un-nested scheduler lock */ + delta = OS_TS_GET() /* Compute the delta time between begin and end */ + - OSSchedLockTimeBegin; + if (OSSchedLockTimeMax < delta) { /* Detect peak value */ + OSSchedLockTimeMax = delta; + } + if (OSSchedLockTimeMaxCur < delta) { /* Detect peak value (for resettable value) */ + OSSchedLockTimeMaxCur = delta; + } + } +} +#endif + + +/* +************************************************************************************************************************ +* RUN ROUND-ROBIN SCHEDULING ALGORITHM +* +* Description: This function is called on every tick to determine if a new task at the same priority needs to execute. +* +* +* Arguments : p_rdy_list is a pointer to the OS_RDY_LIST entry of the ready list at the current priority +* ---------- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list) +{ + OS_TCB *p_tcb; + CPU_SR_ALLOC(); + + + if (OSSchedRoundRobinEn != OS_TRUE) { /* Make sure round-robin has been enabled */ + return; + } + + CPU_CRITICAL_ENTER(); + p_tcb = p_rdy_list->HeadPtr; /* Decrement time quanta counter */ + + if (p_tcb == (OS_TCB *)0) { + CPU_CRITICAL_EXIT(); + return; + } + +#if (OS_CFG_TASK_IDLE_EN > 0u) + if (p_tcb == &OSIdleTaskTCB) { + CPU_CRITICAL_EXIT(); + return; + } +#endif + + if (p_tcb->TimeQuantaCtr > 0u) { + p_tcb->TimeQuantaCtr--; + } + + if (p_tcb->TimeQuantaCtr > 0u) { /* Task not done with its time quanta */ + CPU_CRITICAL_EXIT(); + return; + } + + if (p_rdy_list->HeadPtr == p_rdy_list->TailPtr) { /* See if it's time to time slice current task */ + CPU_CRITICAL_EXIT(); /* ... only if multiple tasks at same priority */ + return; + } + + if (OSSchedLockNestingCtr > 0u) { /* Can't round-robin if the scheduler is locked */ + CPU_CRITICAL_EXIT(); + return; + } + + OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */ + p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */ + if (p_tcb->TimeQuanta == 0u) { /* See if we need to use the default time slice */ + p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; + } else { + p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */ + } + CPU_CRITICAL_EXIT(); +} +#endif + + +/* +************************************************************************************************************************ +* BLOCK A TASK +* +* Description: This function is called to remove a task from the ready list and also insert it in the timer tick list if +* the specified timeout is non-zero. +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task block +* ----- +* +* timeout is the desired timeout +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TaskBlock (OS_TCB *p_tcb, + OS_TICK timeout) +{ +#if (OS_CFG_DYN_TICK_EN > 0u) + OS_TICK elapsed; + + + elapsed = OS_DynTickGet(); +#endif + +#if (OS_CFG_TICK_EN > 0u) + if (timeout > 0u) { /* Add task to tick list if timeout non zero */ +#if (OS_CFG_DYN_TICK_EN > 0u) + (void)OS_TickListInsert(p_tcb, elapsed, (OSTickCtr + elapsed), timeout); +#else + (void)OS_TickListInsert(p_tcb, 0u, OSTickCtr, timeout); +#endif + p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT; + } else { + p_tcb->TaskState = OS_TASK_STATE_PEND; + } +#else + (void)timeout; + p_tcb->TaskState = OS_TASK_STATE_PEND; +#endif + OS_RdyListRemove(p_tcb); +} diff --git a/rtos/uC-OS3/Source/os_dbg.c b/rtos/uC-OS3/Source/os_dbg.c new file mode 100644 index 00000000..fc6ec998 --- /dev/null +++ b/rtos/uC-OS3/Source/os_dbg.c @@ -0,0 +1,520 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* DEBUGGER CONSTANTS +* +* File : os_dbg.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_dbg__c = "$Id: $"; +#endif + + +/* +************************************************************************************************************************ +* CONSTANTS +************************************************************************************************************************ +*/ + +CPU_INT08U const OSDbg_DbgEn = OS_CFG_DBG_EN; /* Debug constants are defined below */ + + +#if (OS_CFG_DBG_EN > 0u) + +/* +************************************************************************************************************************ +* DEBUG DATA +************************************************************************************************************************ +*/ + +CPU_INT08U const OSDbg_ArgChkEn = OS_CFG_ARG_CHK_EN; +CPU_INT08U const OSDbg_AppHooksEn = OS_CFG_APP_HOOKS_EN; + +CPU_INT32U const OSDbg_EndiannessTest = 0x12345678LU; /* Variable to test CPU endianness */ + +CPU_INT08U const OSDbg_CalledFromISRChkEn = OS_CFG_CALLED_FROM_ISR_CHK_EN; + +CPU_INT08U const OSDbg_FlagEn = OS_CFG_FLAG_EN; +OS_FLAG_GRP const OSDbg_FlagGrp = { 0u }; +#if (OS_CFG_FLAG_EN > 0u) +CPU_INT08U const OSDbg_FlagDelEn = OS_CFG_FLAG_DEL_EN; +CPU_INT08U const OSDbg_FlagModeClrEn = OS_CFG_FLAG_MODE_CLR_EN; +CPU_INT08U const OSDbg_FlagPendAbortEn = OS_CFG_FLAG_PEND_ABORT_EN; +CPU_INT16U const OSDbg_FlagGrpSize = sizeof(OS_FLAG_GRP); /* Size in Bytes of OS_FLAG_GRP */ +CPU_INT16U const OSDbg_FlagWidth = sizeof(OS_FLAGS); /* Width (in bytes) of OS_FLAGS */ +#else +CPU_INT08U const OSDbg_FlagDelEn = 0u; +CPU_INT08U const OSDbg_FlagModeClrEn = 0u; +CPU_INT08U const OSDbg_FlagPendAbortEn = 0u; +CPU_INT16U const OSDbg_FlagGrpSize = 0u; +CPU_INT16U const OSDbg_FlagWidth = 0u; +#endif + +OS_MEM const OSDbg_Mem = { 0u }; +CPU_INT08U const OSDbg_MemEn = OS_CFG_MEM_EN; +#if OS_CFG_MEM_EN > 0u +CPU_INT16U const OSDbg_MemSize = sizeof(OS_MEM); /* Mem. Partition header size (bytes) */ +#else +CPU_INT16U const OSDbg_MemSize = 0u; +#endif + + +#if (OS_MSG_EN > 0u) +CPU_INT08U const OSDbg_MsgEn = 1u; +CPU_INT16U const OSDbg_MsgSize = sizeof(OS_MSG); /* OS_MSG size */ +CPU_INT16U const OSDbg_MsgPoolSize = sizeof(OS_MSG_POOL); +CPU_INT16U const OSDbg_MsgQSize = sizeof(OS_MSG_Q); +#else +CPU_INT08U const OSDbg_MsgEn = 0u; +CPU_INT16U const OSDbg_MsgSize = 0u; +CPU_INT16U const OSDbg_MsgPoolSize = 0u; +CPU_INT16U const OSDbg_MsgQSize = 0u; +#endif + + +OS_MUTEX const OSDbg_Mutex = { 0u }; +CPU_INT08U const OSDbg_MutexEn = OS_CFG_MUTEX_EN; +#if (OS_CFG_MUTEX_EN > 0u) +CPU_INT08U const OSDbg_MutexDelEn = OS_CFG_MUTEX_DEL_EN; +CPU_INT08U const OSDbg_MutexPendAbortEn = OS_CFG_MUTEX_PEND_ABORT_EN; +CPU_INT16U const OSDbg_MutexSize = sizeof(OS_MUTEX); /* Size in bytes of OS_MUTEX */ +#else +CPU_INT08U const OSDbg_MutexDelEn = 0u; +CPU_INT08U const OSDbg_MutexPendAbortEn = 0u; +CPU_INT16U const OSDbg_MutexSize = 0u; +#endif + +CPU_INT08U const OSDbg_ObjTypeChkEn = OS_CFG_OBJ_TYPE_CHK_EN; + + +CPU_INT16U const OSDbg_PendListSize = sizeof(OS_PEND_LIST); +CPU_INT16U const OSDbg_PendObjSize = sizeof(OS_PEND_OBJ); + + +CPU_INT16U const OSDbg_PrioMax = OS_CFG_PRIO_MAX; /* Maximum number of priorities */ +CPU_INT16U const OSDbg_PrioTblSize = sizeof(OSPrioTbl); + +CPU_INT16U const OSDbg_PtrSize = sizeof(void *); /* Size in Bytes of a pointer */ + + +OS_Q const OSDbg_Q = { 0u }; +CPU_INT08U const OSDbg_QEn = OS_CFG_Q_EN; +#if (OS_CFG_Q_EN > 0u) +CPU_INT08U const OSDbg_QDelEn = OS_CFG_Q_DEL_EN; +CPU_INT08U const OSDbg_QFlushEn = OS_CFG_Q_FLUSH_EN; +CPU_INT08U const OSDbg_QPendAbortEn = OS_CFG_Q_PEND_ABORT_EN; +CPU_INT16U const OSDbg_QSize = sizeof(OS_Q); /* Size in bytes of OS_Q structure */ +#else +CPU_INT08U const OSDbg_QDelEn = 0u; +CPU_INT08U const OSDbg_QFlushEn = 0u; +CPU_INT08U const OSDbg_QPendAbortEn = 0u; +CPU_INT16U const OSDbg_QSize = 0u; +#endif + + +CPU_INT08U const OSDbg_SchedRoundRobinEn = OS_CFG_SCHED_ROUND_ROBIN_EN; + + +OS_SEM const OSDbg_Sem = { 0u }; +CPU_INT08U const OSDbg_SemEn = OS_CFG_SEM_EN; +#if (OS_CFG_SEM_EN > 0u) +CPU_INT08U const OSDbg_SemDelEn = OS_CFG_SEM_DEL_EN; +CPU_INT08U const OSDbg_SemPendAbortEn = OS_CFG_SEM_PEND_ABORT_EN; +CPU_INT08U const OSDbg_SemSetEn = OS_CFG_SEM_SET_EN; +CPU_INT16U const OSDbg_SemSize = sizeof(OS_SEM); /* Size in bytes of OS_SEM */ +#else +CPU_INT08U const OSDbg_SemDelEn = 0u; +CPU_INT08U const OSDbg_SemPendAbortEn = 0u; +CPU_INT08U const OSDbg_SemSetEn = 0u; +CPU_INT16U const OSDbg_SemSize = 0u; +#endif + + +CPU_INT16U const OSDbg_RdyList = sizeof(OS_RDY_LIST); +CPU_INT32U const OSDbg_RdyListSize = sizeof(OSRdyList); /* Number of bytes in the ready table */ + +CPU_INT08U const OSDbg_StkWidth = sizeof(CPU_STK); + +CPU_INT08U const OSDbg_StatTaskEn = OS_CFG_STAT_TASK_EN; +CPU_INT08U const OSDbg_StatTaskStkChkEn = OS_CFG_STAT_TASK_STK_CHK_EN; + +CPU_INT08U const OSDbg_TaskChangePrioEn = OS_CFG_TASK_CHANGE_PRIO_EN; +CPU_INT08U const OSDbg_TaskDelEn = OS_CFG_TASK_DEL_EN; +CPU_INT08U const OSDbg_TaskQEn = OS_CFG_TASK_Q_EN; +CPU_INT08U const OSDbg_TaskQPendAbortEn = OS_CFG_TASK_Q_PEND_ABORT_EN; +CPU_INT08U const OSDbg_TaskProfileEn = OS_CFG_TASK_PROFILE_EN; +CPU_INT16U const OSDbg_TaskRegTblSize = OS_CFG_TASK_REG_TBL_SIZE; +CPU_INT08U const OSDbg_TaskSemPendAbortEn = OS_CFG_TASK_SEM_PEND_ABORT_EN; +CPU_INT08U const OSDbg_TaskSuspendEn = OS_CFG_TASK_SUSPEND_EN; + + +CPU_INT16U const OSDbg_TCBSize = sizeof(OS_TCB); /* Size in Bytes of OS_TCB */ + +CPU_INT16U const OSDbg_TickListSize = sizeof(OS_TICK_LIST); + +CPU_INT08U const OSDbg_TimeDlyHMSMEn = OS_CFG_TIME_DLY_HMSM_EN; +CPU_INT08U const OSDbg_TimeDlyResumeEn = OS_CFG_TIME_DLY_RESUME_EN; + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) +CPU_INT16U const OSDbg_TLS_TblSize = OS_CFG_TLS_TBL_SIZE * sizeof(OS_TLS); +#else +CPU_INT16U const OSDbg_TLS_TblSize = 0u; +#endif + + +OS_TMR const OSDbg_Tmr = { 0u }; +CPU_INT08U const OSDbg_TmrEn = OS_CFG_TMR_EN; +#if (OS_CFG_TMR_EN > 0u) +CPU_INT08U const OSDbg_TmrDelEn = OS_CFG_TMR_DEL_EN; +CPU_INT16U const OSDbg_TmrSize = sizeof(OS_TMR); +#else +CPU_INT08U const OSDbg_TmrDelEn = 0u; +CPU_INT16U const OSDbg_TmrSize = 0u; +#endif + +CPU_INT16U const OSDbg_VersionNbr = OS_VERSION; + + +/* +************************************************************************************************************************ +* DEBUG DATA +* TOTAL DATA SPACE (i.e. RAM) USED BY uC/OS-III +************************************************************************************************************************ +*/ + +CPU_INT32U const OSDbg_DataSize = sizeof(OSIntNestingCtr) + +#if (OS_CFG_APP_HOOKS_EN > 0u) +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + + sizeof(OS_AppRedzoneHitHookPtr) +#endif + + sizeof(OS_AppTaskCreateHookPtr) + + sizeof(OS_AppTaskDelHookPtr) + + sizeof(OS_AppTaskReturnHookPtr) + + + sizeof(OS_AppIdleTaskHookPtr) + + sizeof(OS_AppStatTaskHookPtr) + + sizeof(OS_AppTaskSwHookPtr) + + sizeof(OS_AppTimeTickHookPtr) +#endif + +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSIdleTaskCtr) +#endif +#if (OS_CFG_TASK_IDLE_EN > 0u) + + sizeof(OSIdleTaskTCB) +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +#if (OS_CFG_TS_EN > 0u) + + sizeof(OSIntDisTimeMax) +#endif +#endif + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) && (OS_CFG_ISR_STK_SIZE > 0) + + sizeof(OSISRStkFree) + + sizeof(OSISRStkUsed) +#endif + +#if (OS_CFG_ISR_STK_SIZE > 0) + + OS_CFG_ISR_STK_SIZE * sizeof(CPU_STK) +#endif + +#if (OS_CFG_TASK_IDLE_EN > 0u) + + OS_CFG_IDLE_TASK_STK_SIZE * sizeof(CPU_STK) +#endif + +#if (OS_CFG_TASK_STAT_EN > 0u) + + OS_CFG_STAT_TASK_STK_SIZE * sizeof(CPU_STK) +#endif + +#if (OS_CFG_TMR_EN > 0u) + + OS_CFG_TMR_TASK_STK_SIZE * sizeof(CPU_STK) +#endif + + + sizeof(OSRunning) + + sizeof(OSInitialized) + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + + sizeof(OSSafetyCriticalStartFlag) +#endif + +#if (OS_CFG_FLAG_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSFlagDbgListPtr) + + sizeof(OSFlagQty) +#endif +#endif + +#if (OS_CFG_MEM_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSMemDbgListPtr) + + sizeof(OSMemQty) +#endif +#endif + +#if (OS_MSG_EN > 0u) + + sizeof(OSMsgPool) +#endif + +#if (OS_CFG_MUTEX_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSMutexDbgListPtr) + + sizeof(OSMutexQty) +#endif +#endif + + + sizeof(OSPrioCur) + + sizeof(OSPrioHighRdy) + + sizeof(OSPrioTbl) + +#if (OS_CFG_Q_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSQDbgListPtr) + + sizeof(OSQQty) +#endif +#endif + + + sizeof(OSRdyList) + + + sizeof(OSSchedLockNestingCtr) + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + + sizeof(OSSchedLockTimeBegin) + + sizeof(OSSchedLockTimeMax) + + sizeof(OSSchedLockTimeMaxCur) +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + + sizeof(OSSchedRoundRobinDfltTimeQuanta) + + sizeof(OSSchedRoundRobinEn) +#endif + +#if (OS_CFG_SEM_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSSemDbgListPtr) +#endif + + sizeof(OSSemQty) +#endif +#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u)) + + sizeof(OSTaskCtxSwCtr) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSTaskDbgListPtr) +#endif +#endif + + + sizeof(OSTaskQty) + + +#if (OS_CFG_STAT_TASK_EN > 0u) + + sizeof(OSStatResetFlag) + + sizeof(OSStatTaskCPUUsage) + + sizeof(OSStatTaskCPUUsageMax) + + sizeof(OSStatTaskCtr) + + sizeof(OSStatTaskCtrMax) + + sizeof(OSStatTaskCtrRun) + + sizeof(OSStatTaskRdy) + + sizeof(OSStatTaskTCB) +#if (OS_CFG_TS_EN > 0u) + + sizeof(OSStatTaskTime) + + sizeof(OSStatTaskTimeMax) +#endif +#endif + +#if (OS_CFG_TICK_EN > 0u) + + sizeof(OSTickCtr) + + sizeof(OSTickList) +#if (OS_CFG_TS_EN > 0u) + + sizeof(OSTickTime) + + sizeof(OSTickTimeMax) +#endif + +#endif + +#if (OS_CFG_TMR_EN > 0u) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSTmrDbgListPtr) + + sizeof(OSTmrListEntries) +#endif + + sizeof(OSTmrListPtr) + + sizeof(OSTmrMutex) + + sizeof(OSTmrCond) +#if (OS_CFG_DBG_EN > 0u) + + sizeof(OSTmrQty) +#endif + + sizeof(OSTmrTaskTCB) + + sizeof(OSTmrTaskTickBase) + + sizeof(OSTmrToTicksMult) +#if (OS_CFG_TS_EN > 0u) + + sizeof(OSTmrTaskTime) + + sizeof(OSTmrTaskTimeMax) +#endif +#endif + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + + sizeof(OSTaskRegNextAvailID) +#endif + + + sizeof(OSTCBCurPtr) + + sizeof(OSTCBHighRdyPtr); + + +/* +************************************************************************************************************************ +* OS DEBUG INITIALIZATION +* +* Description: This function is used to make sure that debug variables that are unused in the application are not +* optimized away. This function might not be necessary for all compilers. In this case, you should simply +* DELETE the code in this function while still leaving the declaration of the function itself. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : (1) This code doesn't do anything, it simply prevents the compiler from optimizing out the 'const' +* variables which are declared in this file. +* (2) You may decide to 'compile out' the code (by using #if 0/#endif) INSIDE the function if your compiler +* DOES NOT optimize out the 'const' variables above. +************************************************************************************************************************ +*/ + +void OS_Dbg_Init (void) +{ + CPU_INT08U const * volatile p_temp08; + CPU_INT16U const * volatile p_temp16; + CPU_INT32U const * volatile p_temp32; + + + p_temp08 = (CPU_INT08U const *)&OSDbg_DbgEn; + + p_temp32 = (CPU_INT32U const *)&OSDbg_DataSize; + + p_temp08 = (CPU_INT08U const *)&OSDbg_ArgChkEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_AppHooksEn; + + p_temp32 = (CPU_INT32U const *)&OSDbg_EndiannessTest; + + p_temp08 = (CPU_INT08U const *)&OSDbg_CalledFromISRChkEn; + + p_temp16 = (CPU_INT16U const *)&OSDbg_FlagGrp; + p_temp08 = (CPU_INT08U const *)&OSDbg_FlagEn; +#if (OS_CFG_FLAG_EN > 0u) + p_temp08 = (CPU_INT08U const *)&OSDbg_FlagDelEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_FlagModeClrEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_FlagPendAbortEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_FlagGrpSize; + p_temp16 = (CPU_INT16U const *)&OSDbg_FlagWidth; +#endif + + p_temp16 = (CPU_INT16U const *)&OSDbg_Mem; + p_temp08 = (CPU_INT08U const *)&OSDbg_MemEn; +#if (OS_CFG_MEM_EN > 0u) + p_temp16 = (CPU_INT16U const *)&OSDbg_MemSize; +#endif + + p_temp08 = (CPU_INT08U const *)&OSDbg_MsgEn; +#if (OS_MSG_EN > 0u) + p_temp16 = (CPU_INT16U const *)&OSDbg_MsgSize; + p_temp16 = (CPU_INT16U const *)&OSDbg_MsgPoolSize; + p_temp16 = (CPU_INT16U const *)&OSDbg_MsgQSize; +#endif + + p_temp16 = (CPU_INT16U const *)&OSDbg_Mutex; + p_temp08 = (CPU_INT08U const *)&OSDbg_MutexEn; +#if (OS_CFG_MUTEX_EN > 0u) + p_temp08 = (CPU_INT08U const *)&OSDbg_MutexDelEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_MutexPendAbortEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_MutexSize; +#endif + + p_temp08 = (CPU_INT08U const *)&OSDbg_ObjTypeChkEn; + + p_temp16 = (CPU_INT16U const *)&OSDbg_PendListSize; + p_temp16 = (CPU_INT16U const *)&OSDbg_PendObjSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_PrioMax; + p_temp16 = (CPU_INT16U const *)&OSDbg_PrioTblSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_PtrSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_Q; + p_temp08 = (CPU_INT08U const *)&OSDbg_QEn; +#if (OS_CFG_Q_EN > 0u) + p_temp08 = (CPU_INT08U const *)&OSDbg_QDelEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_QFlushEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_QPendAbortEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_QSize; +#endif + + p_temp16 = (CPU_INT16U const *)&OSDbg_SchedRoundRobinEn; + + p_temp16 = (CPU_INT16U const *)&OSDbg_Sem; + p_temp08 = (CPU_INT08U const *)&OSDbg_SemEn; +#if (OS_CFG_SEM_EN > 0u) + p_temp08 = (CPU_INT08U const *)&OSDbg_SemDelEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_SemPendAbortEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_SemSetEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_SemSize; +#endif + + p_temp16 = (CPU_INT16U const *)&OSDbg_RdyList; + p_temp32 = (CPU_INT32U const *)&OSDbg_RdyListSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_StkWidth; + + p_temp08 = (CPU_INT08U const *)&OSDbg_StatTaskEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_StatTaskStkChkEn; + + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskChangePrioEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskDelEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskQEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskQPendAbortEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskProfileEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_TaskRegTblSize; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskSemPendAbortEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TaskSuspendEn; + + p_temp16 = (CPU_INT16U const *)&OSDbg_TCBSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_TickListSize; + + p_temp08 = (CPU_INT08U const *)&OSDbg_TimeDlyHMSMEn; + p_temp08 = (CPU_INT08U const *)&OSDbg_TimeDlyResumeEn; + + p_temp16 = (CPU_INT16U const *)&OSDbg_TLS_TblSize; + + p_temp16 = (CPU_INT16U const *)&OSDbg_Tmr; + p_temp08 = (CPU_INT08U const *)&OSDbg_TmrEn; +#if (OS_CFG_TMR_EN > 0u) + p_temp08 = (CPU_INT08U const *)&OSDbg_TmrDelEn; + p_temp16 = (CPU_INT16U const *)&OSDbg_TmrSize; +#endif + + p_temp16 = (CPU_INT16U const *)&OSDbg_VersionNbr; + + p_temp08 = p_temp08; /* Prevent compiler warning for not using 'p_temp' */ + p_temp16 = p_temp16; + p_temp32 = p_temp32; +} +#endif diff --git a/rtos/uC-OS3/Source/os_flag.c b/rtos/uC-OS3/Source/os_flag.c new file mode 100644 index 00000000..6d643cf3 --- /dev/null +++ b/rtos/uC-OS3/Source/os_flag.c @@ -0,0 +1,1298 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* EVENT FLAG MANAGEMENT +* +* File : os_flag.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_flag__c = "$Id: $"; +#endif + + +#if (OS_CFG_FLAG_EN > 0u) + +/* +************************************************************************************************************************ +* CREATE AN EVENT FLAG +* +* Description: This function is called to create an event flag group. +* +* Arguments : p_grp is a pointer to the event flag group to create +* +* p_name is the name of the event flag group +* +* flags contains the initial value to store in the event flag group (typically 0). +* +* p_err is a pointer to an error code which will be returned to your application: +* +* OS_ERR_NONE If the call was successful +* OS_ERR_CREATE_ISR If you attempted to create an Event Flag from an ISR +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the Event Flag after you +* called OSSafetyCriticalStart(). +* OS_ERR_OBJ_PTR_NULL If 'p_grp' is a NULL pointer +* OS_ERR_OBJ_CREATED If the event flag was already created +* +* Returns : none +************************************************************************************************************************ +*/ + +void OSFlagCreate (OS_FLAG_GRP *p_grp, + CPU_CHAR *p_name, + OS_FLAGS flags, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + *p_err = OS_ERR_CREATE_ISR; /* ... can't CREATE from an ISR */ + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_grp->Type == OS_OBJ_TYPE_FLAG) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_grp->Type = OS_OBJ_TYPE_FLAG; /* Set to event flag group type */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_grp->NamePtr = p_name; +#else + (void)p_name; +#endif + p_grp->Flags = flags; /* Set to desired initial value */ +#if (OS_CFG_TS_EN > 0u) + p_grp->TS = 0u; +#endif + OS_PendListInit(&p_grp->PendList); + +#if (OS_CFG_DBG_EN > 0u) + OS_FlagDbgListAdd(p_grp); + OSFlagQty++; +#endif + + OS_TRACE_FLAG_CREATE(p_grp, p_name); + + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DELETE AN EVENT FLAG GROUP +* +* Description: This function deletes an event flag group and readies all tasks pending on the event flag group. +* +* Arguments : p_grp is a pointer to the desired event flag group. +* +* opt determines delete options as follows: +* +* OS_OPT_DEL_NO_PEND Deletes the event flag group ONLY if no task pending +* OS_OPT_DEL_ALWAYS Deletes the event flag group even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* p_err is a pointer to an error code that can contain one of the following values: +* +* OS_ERR_NONE The call was successful and the event flag group was deleted +* OS_ERR_DEL_ISR If you attempted to delete the event flag group from an ISR +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the event flag group after you +* called OSStart() +* OS_ERR_OBJ_PTR_NULL If 'p_grp' is a NULL pointer +* OS_ERR_OBJ_TYPE If you didn't pass a pointer to an event flag group +* OS_ERR_OPT_INVALID An invalid option was specified +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TASK_WAITING One or more tasks were waiting on the event flag group +* +* Returns : == 0 if no tasks were waiting on the event flag group, or upon error. +* > 0 if one or more tasks waiting on the event flag group are now readied and informed. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the event flag +* group MUST check the return code of OSFlagPost and OSFlagPend(). +************************************************************************************************************************ +*/ + +#if (OS_CFG_FLAG_DEL_EN > 0u) +OS_OBJ_QTY OSFlagDel (OS_FLAG_GRP *p_grp, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_OBJ_QTY nbr_tasks; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_FLAG_DEL_ENTER(p_grp, opt); + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_TRACE_FLAG_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME); + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + *p_err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */ + OS_TRACE_FLAG_DEL_EXIT(OS_ERR_DEL_ISR); + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */ + OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_grp->Type != OS_OBJ_TYPE_FLAG) { /* Validate event group object */ + OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + CPU_CRITICAL_ENTER(); + p_pend_list = &p_grp->PendList; + nbr_tasks = 0u; + switch (opt) { + case OS_OPT_DEL_NO_PEND: /* Delete group if no task waiting */ + if (p_pend_list->HeadPtr == (OS_TCB *)0) { +#if (OS_CFG_DBG_EN > 0u) + OS_FlagDbgListRemove(p_grp); + OSFlagQty--; +#endif + OS_TRACE_FLAG_DEL(p_grp); + OS_FlagClr(p_grp); + + CPU_CRITICAL_EXIT(); + + *p_err = OS_ERR_NONE; + } else { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_WAITING; + } + break; + + case OS_OPT_DEL_ALWAYS: /* Always delete the event flag group */ +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* Remove all tasks from the pend list */ + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_DEL); + nbr_tasks++; + } +#if (OS_CFG_DBG_EN > 0u) + OS_FlagDbgListRemove(p_grp); + OSFlagQty--; +#endif + OS_TRACE_FLAG_DEL(p_grp); + + OS_FlagClr(p_grp); + CPU_CRITICAL_EXIT(); + + OSSched(); /* Find highest priority task ready to run */ + *p_err = OS_ERR_NONE; + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OPT_INVALID; + break; + } + + OS_TRACE_FLAG_DEL_EXIT(*p_err); + + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* WAIT ON AN EVENT FLAG GROUP +* +* Description: This function is called to wait for a combination of bits to be set in an event flag group. Your +* application can wait for ANY bit to be set or ALL bits to be set. +* +* Arguments : p_grp is a pointer to the desired event flag group. +* +* flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to wait for. +* The bits you want are specified by setting the corresponding bits in 'flags'. +* e.g. if your application wants to wait for bits 0 and 1 then 'flags' would contain 0x03. +* +* timeout is an optional timeout (in clock ticks) that your task will wait for the +* desired bit combination. If you specify 0, however, your task will wait +* forever at the specified event flag group or, until a message arrives. +* +* opt specifies whether you want ALL bits to be set or ANY of the bits to be set. +* You can specify the 'ONE' of the following arguments: +* +* OS_OPT_PEND_FLAG_CLR_ALL You will wait for ALL bits in 'flags' to be clear (0) +* OS_OPT_PEND_FLAG_CLR_ANY You will wait for ANY bit in 'flags' to be clear (0) +* OS_OPT_PEND_FLAG_SET_ALL You will wait for ALL bits in 'flags' to be set (1) +* OS_OPT_PEND_FLAG_SET_ANY You will wait for ANY bit in 'flags' to be set (1) +* +* You can 'ADD' OS_OPT_PEND_FLAG_CONSUME if you want the event flag to be 'consumed' by +* the call. Example, to wait for any flag in a group AND then clear +* the flags that are present, set 'wait_opt' to: +* +* OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME +* +* You can also 'ADD' the type of pend with 'ONE' of the two option: +* +* OS_OPT_PEND_NON_BLOCKING Task will NOT block if flags are not available +* OS_OPT_PEND_BLOCKING Task will block if flags are not available +* +* p_ts is a pointer to a variable that will receive the timestamp of when the event flag group was +* posted, aborted or the event flag group deleted. If you pass a NULL pointer (i.e. (CPU_TS *)0) +* then you will not get the timestamp. In other words, passing a NULL pointer is valid and +* indicates that you don't need the timestamp. +* +* p_err is a pointer to an error code and can be: +* +* OS_ERR_NONE The desired bits have been set within the specified 'timeout' +* OS_ERR_OBJ_DEL If the event group was deleted +* OS_ERR_OBJ_PTR_NULL If 'p_grp' is a NULL pointer. +* OS_ERR_OBJ_TYPE You are not pointing to an event flag group +* OS_ERR_OPT_INVALID You didn't specify a proper 'opt' argument +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT The wait on the flag was aborted +* OS_ERR_PEND_ISR If you tried to PEND from an ISR +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the flags were not +* available +* OS_ERR_SCHED_LOCKED If you called this function when the scheduler is locked +* OS_ERR_STATUS_INVALID If the pend status has an invalid value +* OS_ERR_TIMEOUT The bit(s) have not been set in the specified 'timeout' +* OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified +* +* Returns : The flags in the event flag group that made the task ready or, 0 if a timeout or an error +* occurred. +* +* Note(s) : This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + CPU_BOOLEAN consume; + OS_FLAGS flags_rdy; + OS_OPT mode; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_FLAG_PEND_ENTER(p_grp, flags, timeout, opt, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + *p_err = OS_ERR_TICK_DISABLED; + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_TICK_DISABLED); + return ((OS_FLAGS)0); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != OS_OPT_PEND_NON_BLOCKING) { + *p_err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_ISR); + return ((OS_FLAGS)0); + } + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */ + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_FLAG_CLR_ALL: + case OS_OPT_PEND_FLAG_CLR_ANY: + case OS_OPT_PEND_FLAG_SET_ALL: + case OS_OPT_PEND_FLAG_SET_ANY: + case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_FLAG_CONSUME: + case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME: + case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME: + case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME: + case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_NON_BLOCKING: + case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_NON_BLOCKING: + case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_NON_BLOCKING: + case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_NON_BLOCKING: + case OS_OPT_PEND_FLAG_CLR_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING): + case OS_OPT_PEND_FLAG_CLR_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING): + case OS_OPT_PEND_FLAG_SET_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING): + case OS_OPT_PEND_FLAG_SET_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING): + break; + + default: + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_grp->Type != OS_OBJ_TYPE_FLAG) { /* Validate that we are pointing at an event flag */ + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + if ((opt & OS_OPT_PEND_FLAG_CONSUME) != 0u) { /* See if we need to consume the flags */ + consume = OS_TRUE; + } else { + consume = OS_FALSE; + } + + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; /* Initialize the returned timestamp */ + } + + mode = opt & OS_OPT_PEND_FLAG_MASK; + CPU_CRITICAL_ENTER(); + switch (mode) { + case OS_OPT_PEND_FLAG_SET_ALL: /* See if all required flags are set */ + flags_rdy = (p_grp->Flags & flags); /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + p_grp->Flags &= ~flags_rdy; /* Clear ONLY the flags that we wanted */ + } + OSTCBCurPtr->FlagsRdy = flags_rdy; /* Save flags that were ready */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_grp->TS; + } +#endif + CPU_CRITICAL_EXIT(); /* Yes, condition met, return to caller */ + OS_TRACE_FLAG_PEND(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* Specified non-blocking so task would block */ + return ((OS_FLAGS)0); + } else { /* Specified blocking so check is scheduler is locked */ + if (OSSchedLockNestingCtr > 0u) { /* See if called with scheduler locked ... */ + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; /* ... can't PEND when locked */ + return (0u); + } + } + /* Lock the scheduler/re-enable interrupts */ + OS_FlagBlock(p_grp, + flags, + opt, + timeout); + CPU_CRITICAL_EXIT(); + } + break; + + case OS_OPT_PEND_FLAG_SET_ANY: + flags_rdy = (p_grp->Flags & flags); /* Extract only the bits we want */ + if (flags_rdy != 0u) { /* See if any flag set */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + p_grp->Flags &= ~flags_rdy; /* Clear ONLY the flags that we got */ + } + OSTCBCurPtr->FlagsRdy = flags_rdy; /* Save flags that were ready */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_grp->TS; + } +#endif + CPU_CRITICAL_EXIT(); /* Yes, condition met, return to caller */ + OS_TRACE_FLAG_PEND(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* Specified non-blocking so task would block */ + return ((OS_FLAGS)0); + } else { /* Specified blocking so check is scheduler is locked */ + if (OSSchedLockNestingCtr > 0u) { /* See if called with scheduler locked ... */ + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; /* ... can't PEND when locked */ + return ((OS_FLAGS)0); + } + } + + OS_FlagBlock(p_grp, + flags, + opt, + timeout); + CPU_CRITICAL_EXIT(); + } + break; + +#if (OS_CFG_FLAG_MODE_CLR_EN > 0u) + case OS_OPT_PEND_FLAG_CLR_ALL: /* See if all required flags are cleared */ + flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); /* Extract only the bits we want */ + if (flags_rdy == flags) { /* Must match ALL the bits that we want */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + p_grp->Flags |= flags_rdy; /* Set ONLY the flags that we wanted */ + } + OSTCBCurPtr->FlagsRdy = flags_rdy; /* Save flags that were ready */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_grp->TS; + } +#endif + CPU_CRITICAL_EXIT(); /* Yes, condition met, return to caller */ + OS_TRACE_FLAG_PEND(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* Specified non-blocking so task would block */ + return ((OS_FLAGS)0); + } else { /* Specified blocking so check is scheduler is locked */ + if (OSSchedLockNestingCtr > 0u) { /* See if called with scheduler locked ... */ + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; /* ... can't PEND when locked */ + return (0); + } + } + + OS_FlagBlock(p_grp, + flags, + opt, + timeout); + CPU_CRITICAL_EXIT(); + } + break; + + case OS_OPT_PEND_FLAG_CLR_ANY: + flags_rdy = (~p_grp->Flags & flags); /* Extract only the bits we want */ + if (flags_rdy != 0u) { /* See if any flag cleared */ + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + p_grp->Flags |= flags_rdy; /* Set ONLY the flags that we got */ + } + OSTCBCurPtr->FlagsRdy = flags_rdy; /* Save flags that were ready */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_grp->TS; + } +#endif + CPU_CRITICAL_EXIT(); /* Yes, condition met, return to caller */ + OS_TRACE_FLAG_PEND(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (flags_rdy); + } else { /* Block task until events occur or timeout */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* Specified non-blocking so task would block */ + return ((OS_FLAGS)0); + } else { /* Specified blocking so check is scheduler is locked */ + if (OSSchedLockNestingCtr > 0u) { /* See if called with scheduler locked ... */ + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; /* ... can't PEND when locked */ + return (0u); + } + } + + OS_FlagBlock(p_grp, + flags, + opt, + timeout); + CPU_CRITICAL_EXIT(); + } + break; +#endif + + default: + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } + + OS_TRACE_FLAG_PEND_BLOCK(p_grp); + + OSSched(); /* Find next HPT ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { + case OS_STATUS_PEND_OK: /* We got the event flags */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_FLAG_PEND(p_grp); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + *p_err = OS_ERR_PEND_ABORT; + break; + + case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */ + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + *p_err = OS_ERR_TIMEOUT; + break; + + case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + *p_err = OS_ERR_OBJ_DEL; + break; + + default: + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_FAILED(p_grp); + *p_err = OS_ERR_STATUS_INVALID; + break; + } + if (*p_err != OS_ERR_NONE) { + OS_TRACE_FLAG_PEND_EXIT(*p_err); + return (0u); + } + + flags_rdy = OSTCBCurPtr->FlagsRdy; + if (consume == OS_TRUE) { /* See if we need to consume the flags */ + switch (mode) { + case OS_OPT_PEND_FLAG_SET_ALL: + case OS_OPT_PEND_FLAG_SET_ANY: /* Clear ONLY the flags we got */ + p_grp->Flags &= ~flags_rdy; + break; + +#if (OS_CFG_FLAG_MODE_CLR_EN > 0u) + case OS_OPT_PEND_FLAG_CLR_ALL: + case OS_OPT_PEND_FLAG_CLR_ANY: /* Set ONLY the flags we got */ + p_grp->Flags |= flags_rdy; + break; +#endif + default: + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } + } + CPU_CRITICAL_EXIT(); + OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; /* Event(s) must have occurred */ + return (flags_rdy); +} + + +/* +************************************************************************************************************************ +* ABORT WAITING ON AN EVENT FLAG GROUP +* +* Description: This function aborts & readies any tasks currently waiting on an event flag group. This function should +* be used to fault-abort the wait on the event flag group, rather than to normally post to the event flag +* group OSFlagPost(). +* +* Arguments : p_grp is a pointer to the event flag group +* +* opt determines the type of ABORT performed: +* +* OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the event flag +* OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the event flag +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE At least one task waiting on the event flag group and was +* readied and informed of the aborted wait; check return value +* for the number of tasks whose wait on the event flag group +* was aborted +* OS_ERR_OBJ_PTR_NULL If 'p_grp' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_grp' is not pointing at an event flag group +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If you called this function from an ISR +* OS_ERR_PEND_ABORT_NONE No task were pending +* +* Returns : == 0 if no tasks were waiting on the event flag group, or upon error. +* > 0 if one or more tasks waiting on the event flag group are now readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_FLAG_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSFlagPendAbort (OS_FLAG_GRP *p_grp, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + OS_OBJ_QTY nbr_tasks; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_OBJ_QTY)0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to Pend Abort from an ISR */ + *p_err = OS_ERR_PEND_ABORT_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_ABORT_1: + case OS_OPT_PEND_ABORT_ALL: + case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED: + case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_grp->Type != OS_OBJ_TYPE_FLAG) { /* Make sure event flag group was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_grp->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on flag group? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_PEND_ABORT_NONE; + return (0u); + } + + nbr_tasks = 0u; +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + + while (p_pend_list->HeadPtr != (OS_TCB *)0) { + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_ABORT); + nbr_tasks++; + if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */ + break; /* No */ + } + } + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + + *p_err = OS_ERR_NONE; + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* GET FLAGS WHO CAUSED TASK TO BECOME READY +* +* Description: This function is called to obtain the flags that caused the task to become ready to run. +* In other words, this function allows you to tell "Who done it!". +* +* Arguments : p_err is a pointer to an error code +* +* OS_ERR_NONE If the call was successful +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ISR If called from an ISR +* +* Returns : The flags that caused the task to be ready. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_FLAGS OSFlagPendGetFlagsRdy (OS_ERR *p_err) +{ + OS_FLAGS flags; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_FLAGS)0); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + *p_err = OS_ERR_PEND_ISR; /* ... can't get from an ISR */ + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + flags = OSTCBCurPtr->FlagsRdy; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (flags); +} + + +/* +************************************************************************************************************************ +* POST EVENT FLAG BIT(S) +* +* Description: This function is called to set or clear some bits in an event flag group. The bits to set or clear are +* specified by a 'bit mask'. +* +* Arguments : p_grp is a pointer to the desired event flag group. +* +* flags If 'opt' (see below) is OS_OPT_POST_FLAG_SET, each bit that is set in 'flags' will +* set the corresponding bit in the event flag group. e.g. to set bits 0, 4 +* and 5 you would set 'flags' to: +* +* 0x31 (note, bit 0 is least significant bit) +* +* If 'opt' (see below) is OS_OPT_POST_FLAG_CLR, each bit that is set in 'flags' will +* CLEAR the corresponding bit in the event flag group. e.g. to clear bits 0, +* 4 and 5 you would specify 'flags' as: +* +* 0x31 (note, bit 0 is least significant bit) +* +* opt indicates whether the flags will be: +* +* OS_OPT_POST_FLAG_SET set +* OS_OPT_POST_FLAG_CLR cleared +* +* you can also 'add' OS_OPT_POST_NO_SCHED to prevent the scheduler from being called. +* +* p_err is a pointer to an error code and can be: +* +* OS_ERR_NONE The call was successful +* OS_ERR_OBJ_PTR_NULL You passed a NULL pointer +* OS_ERR_OBJ_TYPE You are not pointing to an event flag group +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* +* Returns : the new value of the event flags bits that are still set. +* +* Note(s) : 1) The execution time of this function depends on the number of tasks waiting on the event flag group. +************************************************************************************************************************ +*/ + +OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_OPT opt, + OS_ERR *p_err) +{ + + OS_FLAGS flags_cur; + OS_FLAGS flags_rdy; + OS_OPT mode; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + OS_TCB *p_tcb_next; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_FLAG_POST_ENTER(p_grp, flags, opt); + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_FLAG_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */ + OS_TRACE_FLAG_POST_FAILED(p_grp); + OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_grp->Type != OS_OBJ_TYPE_FLAG) { /* Make sure we are pointing to an event flag grp */ + OS_TRACE_FLAG_POST_FAILED(p_grp); + OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + + OS_TRACE_FLAG_POST(p_grp); + + switch (opt) { + case OS_OPT_POST_FLAG_SET: + case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED: + CPU_CRITICAL_ENTER(); + p_grp->Flags |= flags; /* Set the flags specified in the group */ + break; + + case OS_OPT_POST_FLAG_CLR: + case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED: + CPU_CRITICAL_ENTER(); + p_grp->Flags &= ~flags; /* Clear the flags specified in the group */ + break; + + default: + *p_err = OS_ERR_OPT_INVALID; /* INVALID option */ + OS_TRACE_FLAG_POST_EXIT(*p_err); + return (0u); + } +#if (OS_CFG_TS_EN > 0u) + p_grp->TS = ts; +#endif + p_pend_list = &p_grp->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on event flag group? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_NONE; + OS_TRACE_FLAG_POST_EXIT(*p_err); + return (p_grp->Flags); + } + + p_tcb = p_pend_list->HeadPtr; + while (p_tcb != (OS_TCB *)0) { /* Go through all tasks waiting on event flag(s) */ + p_tcb_next = p_tcb->PendNextPtr; + mode = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK; + switch (mode) { + case OS_OPT_PEND_FLAG_SET_ALL: /* See if all req. flags are set for current node */ + flags_rdy = (p_grp->Flags & p_tcb->FlagsPend); + if (flags_rdy == p_tcb->FlagsPend) { + OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */ + flags_rdy, + ts); + } + break; + + case OS_OPT_PEND_FLAG_SET_ANY: /* See if any flag set */ + flags_rdy = (p_grp->Flags & p_tcb->FlagsPend); + if (flags_rdy != 0u) { + OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */ + flags_rdy, + ts); + } + break; + +#if (OS_CFG_FLAG_MODE_CLR_EN > 0u) + case OS_OPT_PEND_FLAG_CLR_ALL: /* See if all req. flags are set for current node */ + flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend); + if (flags_rdy == p_tcb->FlagsPend) { + OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */ + flags_rdy, + ts); + } + break; + + case OS_OPT_PEND_FLAG_CLR_ANY: /* See if any flag set */ + flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend); + if (flags_rdy != 0u) { + OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */ + flags_rdy, + ts); + } + break; +#endif + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_FLAG_PEND_OPT; + OS_TRACE_FLAG_POST_EXIT(*p_err); + return (0u); + } + /* Point to next task waiting for event flag(s) */ + p_tcb = p_tcb_next; + } + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); + } + + CPU_CRITICAL_ENTER(); + flags_cur = p_grp->Flags; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + + OS_TRACE_FLAG_POST_EXIT(*p_err); + return (flags_cur); +} + + +/* +************************************************************************************************************************ +* SUSPEND TASK UNTIL EVENT FLAG(s) RECEIVED OR TIMEOUT OCCURS +* +* Description: This function is internal to uC/OS-III and is used to put a task to sleep until the desired +* event flag bit(s) are set. +* +* Arguments : p_grp is a pointer to the desired event flag group. +* ----- +* +* flags Is a bit pattern indicating which bit(s) (i.e. flags) you wish to check. +* The bits you want are specified by setting the corresponding bits in +* 'flags'. e.g. if your application wants to wait for bits 0 and 1 then +* 'flags' would contain 0x03. +* +* opt specifies whether you want ALL bits to be set/cleared or ANY of the bits +* to be set/cleared. +* You can specify the following argument: +* +* OS_OPT_PEND_FLAG_CLR_ALL You will check ALL bits in 'mask' to be clear (0) +* OS_OPT_PEND_FLAG_CLR_ANY You will check ANY bit in 'mask' to be clear (0) +* OS_OPT_PEND_FLAG_SET_ALL You will check ALL bits in 'mask' to be set (1) +* OS_OPT_PEND_FLAG_SET_ANY You will check ANY bit in 'mask' to be set (1) +* +* timeout is the desired amount of time that the task will wait for the event flag +* bit(s) to be set. +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_FlagBlock (OS_FLAG_GRP *p_grp, + OS_FLAGS flags, + OS_OPT opt, + OS_TICK timeout) +{ + OSTCBCurPtr->FlagsPend = flags; /* Save the flags that we need to wait for */ + OSTCBCurPtr->FlagsOpt = opt; /* Save the type of wait we are doing */ + OSTCBCurPtr->FlagsRdy = 0u; + + OS_Pend((OS_PEND_OBJ *)((void *)p_grp), + OSTCBCurPtr, + OS_TASK_PEND_ON_FLAG, + timeout); +} + + +/* +************************************************************************************************************************ +* CLEAR THE CONTENTS OF AN EVENT FLAG GROUP +* +* Description: This function is called by OSFlagDel() to clear the contents of an event flag group +* + +* Argument(s): p_grp is a pointer to the event flag group to clear +* ----- +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_FlagClr (OS_FLAG_GRP *p_grp) +{ + OS_PEND_LIST *p_pend_list; + + +#if (OS_OBJ_TYPE_REQ > 0u) + p_grp->Type = OS_OBJ_TYPE_NONE; +#endif +#if (OS_CFG_DBG_EN > 0u) + p_grp->NamePtr = (CPU_CHAR *)((void *)"?FLAG"); /* Unknown name */ +#endif + p_grp->Flags = 0u; + p_pend_list = &p_grp->PendList; + OS_PendListInit(p_pend_list); +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE EVENT FLAG GROUP TO/FROM DEBUG LIST +* +* Description: These functions are called by uC/OS-III to add or remove an event flag group from the event flag debug +* list. +* +* Arguments : p_grp is a pointer to the event flag group to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_FlagDbgListAdd (OS_FLAG_GRP *p_grp) +{ + p_grp->DbgNamePtr = (CPU_CHAR *)((void *)" "); + p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0; + if (OSFlagDbgListPtr == (OS_FLAG_GRP *)0) { + p_grp->DbgNextPtr = (OS_FLAG_GRP *)0; + } else { + p_grp->DbgNextPtr = OSFlagDbgListPtr; + OSFlagDbgListPtr->DbgPrevPtr = p_grp; + } + OSFlagDbgListPtr = p_grp; +} + + +void OS_FlagDbgListRemove (OS_FLAG_GRP *p_grp) +{ + OS_FLAG_GRP *p_grp_next; + OS_FLAG_GRP *p_grp_prev; + + + p_grp_prev = p_grp->DbgPrevPtr; + p_grp_next = p_grp->DbgNextPtr; + + if (p_grp_prev == (OS_FLAG_GRP *)0) { + OSFlagDbgListPtr = p_grp_next; + if (p_grp_next != (OS_FLAG_GRP *)0) { + p_grp_next->DbgPrevPtr = (OS_FLAG_GRP *)0; + } + p_grp->DbgNextPtr = (OS_FLAG_GRP *)0; + + } else if (p_grp_next == (OS_FLAG_GRP *)0) { + p_grp_prev->DbgNextPtr = (OS_FLAG_GRP *)0; + p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0; + + } else { + p_grp_prev->DbgNextPtr = p_grp_next; + p_grp_next->DbgPrevPtr = p_grp_prev; + p_grp->DbgNextPtr = (OS_FLAG_GRP *)0; + p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0; + } +} +#endif + + +/* +************************************************************************************************************************ +* MAKE TASK READY-TO-RUN, EVENT(s) OCCURRED +* +* Description: This function is internal to uC/OS-III and is used to make a task ready-to-run because the desired event +* flag bits have been set. +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task to remove +* ----- +* +* flags_rdy contains the bit pattern of the event flags that cause the task to become ready-to-run. +* +* ts is a timestamp associated with the post +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_FlagTaskRdy (OS_TCB *p_tcb, + OS_FLAGS flags_rdy, + CPU_TS ts) +{ +#if (OS_CFG_TS_EN == 0u) + (void)ts; /* Prevent compiler warning for not using 'ts' */ +#endif + + p_tcb->FlagsRdy = flags_rdy; + p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + switch (p_tcb->TaskState) { + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: +#if (OS_CFG_TICK_EN > 0u) + if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) { + OS_TickListRemove(p_tcb); /* Remove from tick list */ + } +#endif + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + p_tcb->TaskState = OS_TASK_STATE_RDY; + break; + + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; + break; + + case OS_TASK_STATE_RDY: + case OS_TASK_STATE_DLY: + case OS_TASK_STATE_DLY_SUSPENDED: + case OS_TASK_STATE_SUSPENDED: + default: + /* Default case. */ + break; + } + OS_PendListRemove(p_tcb); +} +#endif diff --git a/rtos/uC-OS3/Source/os_mem.c b/rtos/uC-OS3/Source/os_mem.c new file mode 100644 index 00000000..38a0252e --- /dev/null +++ b/rtos/uC-OS3/Source/os_mem.c @@ -0,0 +1,391 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MEMORY PARTITION MANAGEMENT +* +* File : os_mem.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_mem__c = "$Id: $"; +#endif + + +#if (OS_CFG_MEM_EN > 0u) +/* +************************************************************************************************************************ +* CREATE A MEMORY PARTITION +* +* Description : Create a fixed-sized memory partition that will be managed by uC/OS-III. +* +* Arguments : p_mem is a pointer to a memory partition control block which is allocated in user memory space. +* +* p_name is a pointer to an ASCII string to provide a name to the memory partition. +* +* p_addr is the starting address of the memory partition +* +* n_blks is the number of memory blocks to create from the partition. +* +* blk_size is the size (in bytes) of each block in the memory partition. +* +* p_err is a pointer to a variable containing an error message which will be set by this function to +* either: +* +* OS_ERR_NONE If the memory partition has been created correctly +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the memory partition after you +* called OSSafetyCriticalStart() +* OS_ERR_MEM_CREATE_ISR If you called this function from an ISR +* OS_ERR_MEM_INVALID_BLKS User specified an invalid number of blocks (must be >= 2) +* OS_ERR_MEM_INVALID_P_ADDR If you are specifying an invalid address for the memory +* storage of the partition or, the block does not align on a +* pointer boundary +* OS_ERR_MEM_INVALID_SIZE User specified an invalid block size +* - must be greater than the size of a pointer +* - must be able to hold an integral number of pointers +* OS_ERR_OBJ_CREATED If the memory partition was already created +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSMemCreate (OS_MEM *p_mem, + CPU_CHAR *p_name, + void *p_addr, + OS_MEM_QTY n_blks, + OS_MEM_SIZE blk_size, + OS_ERR *p_err) +{ +#if (OS_CFG_ARG_CHK_EN > 0u) + CPU_DATA align_msk; +#endif + OS_MEM_QTY i; + OS_MEM_QTY loops; + CPU_INT08U *p_blk; + void **p_link; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_MEM_CREATE_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_addr == (void *)0) { /* Must pass a valid address for the memory part. */ + *p_err = OS_ERR_MEM_INVALID_P_ADDR; + return; + } + if (n_blks < 2u) { /* Must have at least 2 blocks per partition */ + *p_err = OS_ERR_MEM_INVALID_BLKS; + return; + } + if (blk_size < sizeof(void *)) { /* Must contain space for at least a pointer */ + *p_err = OS_ERR_MEM_INVALID_SIZE; + return; + } + align_msk = sizeof(void *) - 1u; + if (align_msk > 0u) { + if (((CPU_ADDR)p_addr & align_msk) != 0u){ /* Must be pointer size aligned */ + *p_err = OS_ERR_MEM_INVALID_P_ADDR; + return; + } + if ((blk_size & align_msk) != 0u) { /* Block size must be a multiple address size */ + *p_err = OS_ERR_MEM_INVALID_SIZE; + return; + } + } +#endif + + p_link = (void **)p_addr; /* Create linked list of free memory blocks */ + p_blk = (CPU_INT08U *)p_addr; + loops = n_blks - 1u; + for (i = 0u; i < loops; i++) { + p_blk += blk_size; + *p_link = (void *)p_blk; /* Save pointer to NEXT block in CURRENT block */ + p_link = (void **)(void *)p_blk; /* Position to NEXT block */ + } + *p_link = (void *)0; /* Last memory block points to NULL */ + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_mem->Type == OS_OBJ_TYPE_MEM) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_mem->Type = OS_OBJ_TYPE_MEM; /* Set the type of object */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_mem->NamePtr = p_name; /* Save name of memory partition */ +#else + (void)p_name; +#endif + p_mem->AddrPtr = p_addr; /* Store start address of memory partition */ + p_mem->FreeListPtr = p_addr; /* Initialize pointer to pool of free blocks */ + p_mem->NbrFree = n_blks; /* Store number of free blocks in MCB */ + p_mem->NbrMax = n_blks; + p_mem->BlkSize = blk_size; /* Store block size of each memory blocks */ + +#if (OS_CFG_DBG_EN > 0u) + OS_MemDbgListAdd(p_mem); + OSMemQty++; +#endif + + OS_TRACE_MEM_CREATE(p_mem, p_name); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* GET A MEMORY BLOCK +* +* Description : Get a memory block from a partition. +* +* Arguments : p_mem is a pointer to the memory partition control block +* +* p_err is a pointer to a variable containing an error message which will be set by this function to +* either: +* +* OS_ERR_NONE If the memory partition has been created correctly +* OS_ERR_MEM_INVALID_P_MEM If you passed a NULL pointer for 'p_mem' +* OS_ERR_MEM_NO_FREE_BLKS If there are no more free memory blocks to allocate to the caller +* OS_ERR_OBJ_TYPE If 'p_mem' is not pointing at a memory partition +* +* Returns : A pointer to a memory block if no error is detected +* A pointer to NULL if an error is detected +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void *OSMemGet (OS_MEM *p_mem, + OS_ERR *p_err) +{ + void *p_blk; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + + OS_TRACE_MEM_GET_ENTER(p_mem); + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mem == (OS_MEM *)0) { /* Must point to a valid memory partition */ + OS_TRACE_MEM_GET_FAILED(p_mem); + OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_INVALID_P_MEM); + *p_err = OS_ERR_MEM_INVALID_P_MEM; + return ((void *)0); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* Make sure the memory block was created */ + OS_TRACE_MEM_GET_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return ((void *)0); + } +#endif + + + CPU_CRITICAL_ENTER(); + if (p_mem->NbrFree == 0u) { /* See if there are any free memory blocks */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MEM_GET_FAILED(p_mem); + OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_NO_FREE_BLKS); + *p_err = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */ + return ((void *)0); /* Return NULL pointer to caller */ + } + p_blk = p_mem->FreeListPtr; /* Yes, point to next free memory block */ + p_mem->FreeListPtr = *(void **)p_blk; /* Adjust pointer to new free list */ + p_mem->NbrFree--; /* One less memory block in this partition */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MEM_GET(p_mem); + OS_TRACE_MEM_GET_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; /* No error */ + return (p_blk); /* Return memory block to caller */ +} + + +/* +************************************************************************************************************************ +* RELEASE A MEMORY BLOCK +* +* Description : Returns a memory block to a partition. +* +* Arguments : p_mem is a pointer to the memory partition control block +* +* p_blk is a pointer to the memory block being released. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE If the memory block was inserted into the partition +* OS_ERR_MEM_FULL If you are returning a memory block to an already FULL memory +* partition (You freed more blocks than you allocated!) +* OS_ERR_MEM_INVALID_P_BLK If you passed a NULL pointer for the block to release. +* OS_ERR_MEM_INVALID_P_MEM If you passed a NULL pointer for 'p_mem' +* OS_ERR_OBJ_TYPE If 'p_mem' is not pointing at a memory partition +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSMemPut (OS_MEM *p_mem, + void *p_blk, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OS_TRACE_MEM_PUT_ENTER(p_mem, p_blk); + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mem == (OS_MEM *)0) { /* Must point to a valid memory partition */ + OS_TRACE_MEM_PUT_FAILED(p_mem); + OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_MEM); + *p_err = OS_ERR_MEM_INVALID_P_MEM; + return; + } + if (p_blk == (void *)0) { /* Must release a valid block */ + OS_TRACE_MEM_PUT_FAILED(p_mem); + OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_BLK); + *p_err = OS_ERR_MEM_INVALID_P_BLK; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* Make sure the memory block was created */ + OS_TRACE_MEM_PUT_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif + + + CPU_CRITICAL_ENTER(); + if (p_mem->NbrFree >= p_mem->NbrMax) { /* Make sure all blocks not already returned */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MEM_PUT_FAILED(p_mem); + OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_FULL); + *p_err = OS_ERR_MEM_FULL; + return; + } + *(void **)p_blk = p_mem->FreeListPtr; /* Insert released block into free block list */ + p_mem->FreeListPtr = p_blk; + p_mem->NbrFree++; /* One more memory block in this partition */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MEM_PUT(p_mem); + OS_TRACE_MEM_PUT_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; /* Notify caller that memory block was released */ +} + + +/* +************************************************************************************************************************ +* ADD MEMORY PARTITION TO DEBUG LIST +* +* Description : This function is called by OSMemCreate() to add the memory partition to the debug table. +* +* Arguments : p_mem Is a pointer to the memory partition +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_MemDbgListAdd (OS_MEM *p_mem) +{ + p_mem->DbgPrevPtr = (OS_MEM *)0; + if (OSMemDbgListPtr == (OS_MEM *)0) { + p_mem->DbgNextPtr = (OS_MEM *)0; + } else { + p_mem->DbgNextPtr = OSMemDbgListPtr; + OSMemDbgListPtr->DbgPrevPtr = p_mem; + } + OSMemDbgListPtr = p_mem; +} +#endif + + +/* +************************************************************************************************************************ +* INITIALIZE MEMORY PARTITION MANAGER +* +* Description : This function is called by uC/OS-III to initialize the memory partition manager. Your +* application MUST NOT call this function. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_MemInit (OS_ERR *p_err) +{ +#if (OS_CFG_DBG_EN > 0u) + OSMemDbgListPtr = (OS_MEM *)0; + OSMemQty = 0u; +#endif + *p_err = OS_ERR_NONE; +} +#endif diff --git a/rtos/uC-OS3/Source/os_msg.c b/rtos/uC-OS3/Source/os_msg.c new file mode 100644 index 00000000..e4d78f22 --- /dev/null +++ b/rtos/uC-OS3/Source/os_msg.c @@ -0,0 +1,349 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MESSAGE HANDLING SERVICES +* +* File : os_msg.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_msg__c = "$Id: $"; +#endif + + +#if (OS_MSG_EN > 0u) + +/* +************************************************************************************************************************ +* INITIALIZE THE POOL OF 'OS_MSG' +* +* Description: This function is called by OSInit() to initialize the free list of OS_MSGs. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_MSG_POOL_NULL_PTR +* OS_ERR_MSG_POOL_EMPTY +* OS_ERR_NONE +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MsgPoolInit (OS_ERR *p_err) +{ + OS_MSG *p_msg1; + OS_MSG *p_msg2; + OS_MSG_QTY i; + OS_MSG_QTY loops; + + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (OSCfg_MsgPoolBasePtr == (OS_MSG *)0) { + *p_err = OS_ERR_MSG_POOL_NULL_PTR; + return; + } + if (OSCfg_MsgPoolSize == 0u) { + *p_err = OS_ERR_MSG_POOL_EMPTY; + return; + } +#endif + + p_msg1 = OSCfg_MsgPoolBasePtr; + p_msg2 = OSCfg_MsgPoolBasePtr; + p_msg2++; + loops = OSCfg_MsgPoolSize - 1u; + for (i = 0u; i < loops; i++) { /* Init. list of free OS_MSGs */ + p_msg1->NextPtr = p_msg2; + p_msg1->MsgPtr = (void *)0; + p_msg1->MsgSize = 0u; +#if (OS_CFG_TS_EN > 0u) + p_msg1->MsgTS = 0u; +#endif + p_msg1++; + p_msg2++; + } + p_msg1->NextPtr = (OS_MSG *)0; /* Last OS_MSG */ + p_msg1->MsgPtr = (void *)0; + p_msg1->MsgSize = 0u; +#if (OS_CFG_TS_EN > 0u) + p_msg1->MsgTS = 0u; +#endif + + OSMsgPool.NextPtr = OSCfg_MsgPoolBasePtr; + OSMsgPool.NbrFree = OSCfg_MsgPoolSize; + OSMsgPool.NbrUsed = 0u; +#if (OS_CFG_DBG_EN > 0u) + OSMsgPool.NbrUsedMax = 0u; +#endif + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* RELEASE ALL MESSAGE IN MESSAGE QUEUE +* +* Description: This function returns all the messages in a message queue to the free list. +* +* Arguments : p_msg_q is a pointer to the OS_MSG_Q structure containing messages to free. +* ------- +* +* Returns : the number of OS_MSGs returned to the free list +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +OS_MSG_QTY OS_MsgQFreeAll (OS_MSG_Q *p_msg_q) +{ + OS_MSG *p_msg; + OS_MSG_QTY qty; + + + + qty = p_msg_q->NbrEntries; /* Get the number of OS_MSGs being freed */ + if (p_msg_q->NbrEntries > 0u) { + p_msg = p_msg_q->InPtr; /* Point to end of message chain */ + p_msg->NextPtr = OSMsgPool.NextPtr; + OSMsgPool.NextPtr = p_msg_q->OutPtr; /* Point to beginning of message chain */ + OSMsgPool.NbrUsed -= p_msg_q->NbrEntries; /* Update statistics for free list of messages */ + OSMsgPool.NbrFree += p_msg_q->NbrEntries; + p_msg_q->NbrEntries = 0u; /* Flush the message queue */ +#if (OS_CFG_DBG_EN > 0u) + p_msg_q->NbrEntriesMax = 0u; +#endif + p_msg_q->InPtr = (OS_MSG *)0; + p_msg_q->OutPtr = (OS_MSG *)0; + } + return (qty); +} + + +/* +************************************************************************************************************************ +* INITIALIZE A MESSAGE QUEUE +* +* Description: This function is called to initialize a message queue +* +* Arguments : p_msg_q is a pointer to the message queue to initialize +* ------- +* +* size is the maximum number of entries that a message queue can have. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MsgQInit (OS_MSG_Q *p_msg_q, + OS_MSG_QTY size) +{ + p_msg_q->NbrEntriesSize = size; + p_msg_q->NbrEntries = 0u; +#if (OS_CFG_DBG_EN > 0u) + p_msg_q->NbrEntriesMax = 0u; +#endif + p_msg_q->InPtr = (OS_MSG *)0; + p_msg_q->OutPtr = (OS_MSG *)0; +} + + +/* +************************************************************************************************************************ +* RETRIEVE MESSAGE FROM MESSAGE QUEUE +* +* Description: This function retrieves a message from a message queue +* +* Arguments : p_msg_q is a pointer to the message queue where we want to extract the message from +* ------- +* +* p_msg_size is a pointer to where the size (in bytes) of the message will be placed +* +* p_ts is a pointer to where the time stamp will be placed +* +* p_err is a pointer to an error code that will be returned from this call. +* +* OS_ERR_Q_EMPTY +* OS_ERR_NONE +* +* Returns : The message (a pointer) +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void *OS_MsgQGet (OS_MSG_Q *p_msg_q, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + OS_MSG *p_msg; + void *p_void; + + +#if (OS_CFG_TS_EN == 0u) + (void)p_ts; /* Prevent compiler warning for not using 'ts' */ +#endif + + if (p_msg_q->NbrEntries == 0u) { /* Is the queue empty? */ + *p_msg_size = 0u; /* Yes */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + *p_err = OS_ERR_Q_EMPTY; + return ((void *)0); + } + + p_msg = p_msg_q->OutPtr; /* No, get the next message to extract from the queue */ + p_void = p_msg->MsgPtr; + *p_msg_size = p_msg->MsgSize; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_msg->MsgTS; + } +#endif + + p_msg_q->OutPtr = p_msg->NextPtr; /* Point to next message to extract */ + + if (p_msg_q->OutPtr == (OS_MSG *)0) { /* Are there any more messages in the queue? */ + p_msg_q->InPtr = (OS_MSG *)0; /* No */ + p_msg_q->NbrEntries = 0u; + } else { + p_msg_q->NbrEntries--; /* Yes, One less message in the queue */ + } + + p_msg->NextPtr = OSMsgPool.NextPtr; /* Return message control block to free list */ + OSMsgPool.NextPtr = p_msg; + OSMsgPool.NbrFree++; + OSMsgPool.NbrUsed--; + + *p_err = OS_ERR_NONE; + return (p_void); +} + + +/* +************************************************************************************************************************ +* DEPOSIT MESSAGE IN MESSAGE QUEUE +* +* Description: This function places a message in a message queue +* +* Arguments : p_msg_q is a pointer to the OS_TCB of the task to post the message to +* ------- +* +* p_void is a pointer to the message to send. +* +* msg_size is the size of the message (in bytes) +* +* opt specifies whether the message will be posted in FIFO or LIFO order +* +* OS_OPT_POST_FIFO +* OS_OPT_POST_LIFO +* +* ts is a timestamp as to when the message was posted +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_Q_MAX if the queue is full +* OS_ERR_MSG_POOL_EMPTY if we no longer have any OS_MSG to use +* OS_ERR_NONE the message was deposited in the queue +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MsgQPut (OS_MSG_Q *p_msg_q, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + CPU_TS ts, + OS_ERR *p_err) +{ + OS_MSG *p_msg; + OS_MSG *p_msg_in; + + +#if (OS_CFG_TS_EN == 0u) + (void)ts; /* Prevent compiler warning for not using 'ts' */ +#endif + + if (p_msg_q->NbrEntries >= p_msg_q->NbrEntriesSize) { + *p_err = OS_ERR_Q_MAX; /* Message queue cannot accept any more messages */ + return; + } + + if (OSMsgPool.NbrFree == 0u) { + *p_err = OS_ERR_MSG_POOL_EMPTY; /* No more OS_MSG to use */ + return; + } + + p_msg = OSMsgPool.NextPtr; /* Remove message control block from free list */ + OSMsgPool.NextPtr = p_msg->NextPtr; + OSMsgPool.NbrFree--; + OSMsgPool.NbrUsed++; + +#if (OS_CFG_DBG_EN > 0u) + if (OSMsgPool.NbrUsedMax < OSMsgPool.NbrUsed) { + OSMsgPool.NbrUsedMax = OSMsgPool.NbrUsed; + } +#endif + + if (p_msg_q->NbrEntries == 0u) { /* Is this first message placed in the queue? */ + p_msg_q->InPtr = p_msg; /* Yes */ + p_msg_q->OutPtr = p_msg; + p_msg_q->NbrEntries = 1u; + p_msg->NextPtr = (OS_MSG *)0; + } else { /* No */ + if ((opt & OS_OPT_POST_LIFO) == OS_OPT_POST_FIFO) { /* Is it FIFO or LIFO? */ + p_msg_in = p_msg_q->InPtr; /* FIFO, add to the head */ + p_msg_in->NextPtr = p_msg; + p_msg_q->InPtr = p_msg; + p_msg->NextPtr = (OS_MSG *)0; + } else { + p_msg->NextPtr = p_msg_q->OutPtr; /* LIFO, add to the tail */ + p_msg_q->OutPtr = p_msg; + } + p_msg_q->NbrEntries++; + } + +#if (OS_CFG_DBG_EN > 0u) + if (p_msg_q->NbrEntriesMax < p_msg_q->NbrEntries) { + p_msg_q->NbrEntriesMax = p_msg_q->NbrEntries; + } +#endif + + p_msg->MsgPtr = p_void; /* Deposit message in the message queue entry */ + p_msg->MsgSize = msg_size; +#if (OS_CFG_TS_EN > 0u) + p_msg->MsgTS = ts; +#endif + *p_err = OS_ERR_NONE; +} +#endif diff --git a/rtos/uC-OS3/Source/os_mutex.c b/rtos/uC-OS3/Source/os_mutex.c new file mode 100644 index 00000000..1cd40c2c --- /dev/null +++ b/rtos/uC-OS3/Source/os_mutex.c @@ -0,0 +1,1129 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MUTEX MANAGEMENT +* +* File : os_mutex.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_mutex__c = "$Id: $"; +#endif + + +#if (OS_CFG_MUTEX_EN > 0u) +/* +************************************************************************************************************************ +* CREATE A MUTEX +* +* Description: This function creates a mutex. +* +* Arguments : p_mutex is a pointer to the mutex to initialize. Your application is responsible for allocating +* storage for the mutex. +* +* p_name is a pointer to the name you would like to give the mutex. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE If the call was successful +* OS_ERR_CREATE_ISR If you called this function from an ISR +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the mutex after you called +* OSSafetyCriticalStart() +* OS_ERR_OBJ_PTR_NULL If 'p_mutex' is a NULL pointer +* OS_ERR_OBJ_CREATED If the mutex was already created +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSMutexCreate (OS_MUTEX *p_mutex, + CPU_CHAR *p_name, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to be called from an ISR */ + *p_err = OS_ERR_CREATE_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mutex == (OS_MUTEX *)0) { /* Validate 'p_mutex' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_mutex->Type == OS_OBJ_TYPE_MUTEX) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_mutex->Type = OS_OBJ_TYPE_MUTEX; /* Mark the data structure as a mutex */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_mutex->NamePtr = p_name; +#else + (void)p_name; +#endif + p_mutex->MutexGrpNextPtr = (OS_MUTEX *)0; + p_mutex->OwnerTCBPtr = (OS_TCB *)0; + p_mutex->OwnerNestingCtr = 0u; /* Mutex is available */ +#if (OS_CFG_TS_EN > 0u) + p_mutex->TS = 0u; +#endif + OS_PendListInit(&p_mutex->PendList); /* Initialize the waiting list */ + +#if (OS_CFG_DBG_EN > 0u) + OS_MutexDbgListAdd(p_mutex); + OSMutexQty++; +#endif + + OS_TRACE_MUTEX_CREATE(p_mutex, p_name); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DELETE A MUTEX +* +* Description: This function deletes a mutex and readies all tasks pending on the mutex. +* +* Arguments : p_mutex is a pointer to the mutex to delete +* +* opt determines delete options as follows: +* +* OS_OPT_DEL_NO_PEND Delete mutex ONLY if no task pending +* OS_OPT_DEL_ALWAYS Deletes the mutex even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the mutex was deleted +* OS_ERR_DEL_ISR If you attempted to delete the mutex from an ISR +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the mutex after you called +* OSStart() +* OS_ERR_OBJ_PTR_NULL If 'p_mutex' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_mutex' is not pointing to a mutex +* OS_ERR_OPT_INVALID An invalid option was specified +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex +* +* Returns : == 0 if no tasks were waiting on the mutex, or upon error. +* > 0 if one or more tasks waiting on the mutex are now readied and informed. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the mutex MUST +* check the return code of OSMutexPend(). +* +* 2) Because ALL tasks pending on the mutex will be readied, you MUST be careful in applications where the +* mutex is used for mutual exclusion because the resource(s) will no longer be guarded by the mutex. +************************************************************************************************************************ +*/ + +#if (OS_CFG_MUTEX_DEL_EN > 0u) +OS_OBJ_QTY OSMutexDel (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_OBJ_QTY nbr_tasks; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + OS_TCB *p_tcb_owner; + CPU_TS ts; +#if (OS_CFG_MUTEX_EN > 0u) + OS_PRIO prio_new; +#endif + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_MUTEX_DEL_ENTER(p_mutex, opt); + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME); + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to delete a mutex from an ISR */ + OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_DEL_ISR); + *p_err = OS_ERR_DEL_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mutex == (OS_MUTEX *)0) { /* Validate 'p_mutex' */ + OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ + OS_TRACE_MUTEX_DEL_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_mutex->PendList; + nbr_tasks = 0u; + switch (opt) { + case OS_OPT_DEL_NO_PEND: /* Delete mutex only if no task waiting */ + if (p_pend_list->HeadPtr == (OS_TCB *)0) { +#if (OS_CFG_DBG_EN > 0u) + OS_MutexDbgListRemove(p_mutex); + OSMutexQty--; +#endif + OS_TRACE_MUTEX_DEL(p_mutex); + if (p_mutex->OwnerTCBPtr != (OS_TCB *)0) { /* Does the mutex belong to a task? */ + OS_MutexGrpRemove(p_mutex->OwnerTCBPtr, p_mutex); /* yes, remove it from the task group. */ + } + OS_MutexClr(p_mutex); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + } else { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_WAITING; + } + break; + + case OS_OPT_DEL_ALWAYS: /* Always delete the mutex */ +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* Remove all tasks from the pend list */ + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_DEL); + nbr_tasks++; + } +#if (OS_CFG_DBG_EN > 0u) + OS_MutexDbgListRemove(p_mutex); + OSMutexQty--; +#endif + OS_TRACE_MUTEX_DEL(p_mutex); + p_tcb_owner = p_mutex->OwnerTCBPtr; + if (p_tcb_owner != (OS_TCB *)0) { /* Does the mutex belong to a task? */ + OS_MutexGrpRemove(p_tcb_owner, p_mutex); /* yes, remove it from the task group. */ + } + + + if (p_tcb_owner != (OS_TCB *)0) { /* Did we had to change the prio of owner? */ + if (p_tcb_owner->Prio != p_tcb_owner->BasePrio) { + prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); + prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new; + OS_TaskChangePrio(p_tcb_owner, prio_new); + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio); + } + } + + OS_MutexClr(p_mutex); + CPU_CRITICAL_EXIT(); + OSSched(); /* Find highest priority task ready to run */ + *p_err = OS_ERR_NONE; + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OPT_INVALID; + break; + } + OS_TRACE_MUTEX_DEL_EXIT(*p_err); + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* PEND ON MUTEX +* +* Description: This function waits for a mutex. +* +* Arguments : p_mutex is a pointer to the mutex +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for the +* resource up to the amount of time (in 'ticks') specified by this argument. If you specify +* 0, however, your task will wait forever at the specified mutex or, until the resource +* becomes available. +* +* opt determines whether the user wants to block if the mutex is available or not: +* +* OS_OPT_PEND_BLOCKING +* OS_OPT_PEND_NON_BLOCKING +* +* p_ts is a pointer to a variable that will receive the timestamp of when the mutex was posted or +* pend aborted or the mutex deleted. If you pass a NULL pointer (i.e. (CPU_TS *)0) then you +* will not get the timestamp. In other words, passing a NULL pointer is valid and indicates +* that you don't need the timestamp. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and your task owns the resource +* OS_ERR_MUTEX_OWNER If calling task already owns the mutex +* OS_ERR_MUTEX_OVF Mutex nesting counter overflowed +* OS_ERR_OBJ_DEL If 'p_mutex' was deleted +* OS_ERR_OBJ_PTR_NULL If 'p_mutex' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_mutex' is not pointing at a mutex +* OS_ERR_OPT_INVALID If you didn't specify a valid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT If the pend was aborted by another task +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the mutex was not +* available +* OS_ERR_SCHED_LOCKED If you called this function when the scheduler is locked +* OS_ERR_STATUS_INVALID If the pend status has an invalid value +* OS_ERR_TIMEOUT The mutex was not received within the specified timeout +* OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified +* +* Returns : none +* +* Note(s) : This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +void OSMutexPend (OS_MUTEX *p_mutex, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + OS_TCB *p_tcb; + CPU_SR_ALLOC(); + + +#if (OS_CFG_TS_EN == 0u) + (void)p_ts; /* Prevent compiler warning for not using 'ts' */ +#endif + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OS_TRACE_MUTEX_PEND_ENTER(p_mutex, timeout, opt, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + *p_err = OS_ERR_TICK_DISABLED; + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_TICK_DISABLED); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_ISR); + *p_err = OS_ERR_PEND_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mutex == (OS_MUTEX *)0) { /* Validate arguments */ + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_BLOCKING: + case OS_OPT_PEND_NON_BLOCKING: + break; + + default: + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_mutex->OwnerNestingCtr == 0u) { /* Resource available? */ + p_mutex->OwnerTCBPtr = OSTCBCurPtr; /* Yes, caller may proceed */ + p_mutex->OwnerNestingCtr = 1u; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_mutex->TS; + } +#endif + OS_MutexGrpAdd(OSTCBCurPtr, p_mutex); /* Add mutex to owner's group */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_PEND(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return; + } + + if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) { /* See if current task is already the owner of the mutex*/ + if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)-1) { + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OVF); + *p_err = OS_ERR_MUTEX_OVF; + return; + } + p_mutex->OwnerNestingCtr++; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_mutex->TS; + } +#endif + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_MUTEX_OWNER); + *p_err = OS_ERR_MUTEX_OWNER; /* Indicate that current task already owns the mutex */ + return; + } + + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */ + CPU_CRITICAL_EXIT(); +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */ + return; + } else { + if (OSSchedLockNestingCtr > 0u) { /* Can't pend when the scheduler is locked */ + CPU_CRITICAL_EXIT(); +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; + return; + } + } + + p_tcb = p_mutex->OwnerTCBPtr; /* Point to the TCB of the Mutex owner */ + if (p_tcb->Prio > OSTCBCurPtr->Prio) { /* See if mutex owner has a lower priority than current */ + OS_TaskChangePrio(p_tcb, OSTCBCurPtr->Prio); + OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb, p_tcb->Prio); + } + + OS_Pend((OS_PEND_OBJ *)((void *)p_mutex), /* Block task pending on Mutex */ + OSTCBCurPtr, + OS_TASK_PEND_ON_MUTEX, + timeout); + + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_PEND_BLOCK(p_mutex); + OSSched(); /* Find the next highest priority task ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { + case OS_STATUS_PEND_OK: /* We got the mutex */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_MUTEX_PEND(p_mutex); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + *p_err = OS_ERR_PEND_ABORT; + break; + + case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get mutex within timeout */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + *p_err = OS_ERR_TIMEOUT; + break; + + case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + *p_err = OS_ERR_OBJ_DEL; + break; + + default: + OS_TRACE_MUTEX_PEND_FAILED(p_mutex); + *p_err = OS_ERR_STATUS_INVALID; + break; + } + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_PEND_EXIT(*p_err); +} + + +/* +************************************************************************************************************************ +* ABORT WAITING ON A MUTEX +* +* Description: This function aborts & readies any tasks currently waiting on a mutex. This function should be used +* to fault-abort the wait on the mutex, rather than to normally signal the mutex via OSMutexPost(). +* +* Arguments : p_mutex is a pointer to the mutex +* +* opt determines the type of ABORT performed: +* +* OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the mutex +* OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the mutex +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE At least one task waiting on the mutex was readied and +* informed of the aborted wait; check return value for the +* number of tasks whose wait on the mutex was aborted +* OS_ERR_OBJ_PTR_NULL If 'p_mutex' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_mutex' is not pointing at a mutex +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If you attempted to call this function from an ISR +* OS_ERR_PEND_ABORT_NONE No task were pending +* +* Returns : == 0 if no tasks were waiting on the mutex, or upon error. +* > 0 if one or more tasks waiting on the mutex are now readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_MUTEX_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSMutexPendAbort (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + OS_TCB *p_tcb_owner; + CPU_TS ts; + OS_OBJ_QTY nbr_tasks; + OS_PRIO prio_new; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_OBJ_QTY)0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to Pend Abort from an ISR */ + *p_err = OS_ERR_PEND_ABORT_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mutex == (OS_MUTEX *)0) { /* Validate 'p_mutex' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_ABORT_1: + case OS_OPT_PEND_ABORT_ALL: + case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED: + case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_mutex->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_PEND_ABORT_NONE; + return (0u); + } + + nbr_tasks = 0u; +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { + p_tcb = p_pend_list->HeadPtr; + + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_ABORT); + p_tcb_owner = p_mutex->OwnerTCBPtr; + prio_new = p_tcb_owner->Prio; + if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) && + (p_tcb_owner->Prio == p_tcb->Prio)) { /* Has the owner inherited a priority? */ + prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); + prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new; + } + + if(prio_new != p_tcb_owner->Prio) { + OS_TaskChangePrio(p_tcb_owner, prio_new); + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio); + } + + nbr_tasks++; + if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */ + break; /* No */ + } + } + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + + *p_err = OS_ERR_NONE; + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* POST TO A MUTEX +* +* Description: This function signals a mutex. +* +* Arguments : p_mutex is a pointer to the mutex +* +* opt is an option you can specify to alter the behavior of the post. The choices are: +* +* OS_OPT_POST_NONE No special option selected +* OS_OPT_POST_NO_SCHED If you don't want the scheduler to be called after the post. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the mutex was signaled +* OS_ERR_MUTEX_NESTING Mutex owner nested its use of the mutex +* OS_ERR_MUTEX_NOT_OWNER If the task posting is not the Mutex owner +* OS_ERR_OBJ_PTR_NULL If 'p_mutex' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_mutex' is not pointing at a mutex +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_POST_ISR If you attempted to post from an ISR +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSMutexPost (OS_MUTEX *p_mutex, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + OS_PRIO prio_new; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OS_TRACE_MUTEX_POST_ENTER(p_mutex, opt); + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + OS_TRACE_MUTEX_POST_FAILED(p_mutex); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_POST_ISR); + *p_err = OS_ERR_POST_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_mutex == (OS_MUTEX *)0) { /* Validate 'p_mutex' */ + OS_TRACE_MUTEX_POST_FAILED(p_mutex); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_POST_NONE: + case OS_OPT_POST_NO_SCHED: + break; + + default: + OS_TRACE_MUTEX_POST_FAILED(p_mutex); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_mutex->Type != OS_OBJ_TYPE_MUTEX) { /* Make sure mutex was created */ + OS_TRACE_MUTEX_POST_FAILED(p_mutex); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) { /* Make sure the mutex owner is releasing the mutex */ + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_POST_FAILED(p_mutex); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NOT_OWNER); + *p_err = OS_ERR_MUTEX_NOT_OWNER; + return; + } + + OS_TRACE_MUTEX_POST(p_mutex); + +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ + p_mutex->TS = ts; +#else + ts = 0u; +#endif + p_mutex->OwnerNestingCtr--; /* Decrement owner's nesting counter */ + if (p_mutex->OwnerNestingCtr > 0u) { /* Are we done with all nestings? */ + CPU_CRITICAL_EXIT(); /* No */ + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_MUTEX_NESTING); + *p_err = OS_ERR_MUTEX_NESTING; + return; + } + + OS_MutexGrpRemove(OSTCBCurPtr, p_mutex); /* Remove mutex from owner's group */ + + p_pend_list = &p_mutex->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */ + p_mutex->OwnerTCBPtr = (OS_TCB *)0; /* No */ + p_mutex->OwnerNestingCtr = 0u; + CPU_CRITICAL_EXIT(); + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return; + } + /* Yes */ + if (OSTCBCurPtr->Prio != OSTCBCurPtr->BasePrio) { /* Has owner inherited a priority? */ + prio_new = OS_MutexGrpPrioFindHighest(OSTCBCurPtr); /* Yes, find highest priority pending */ + prio_new = (prio_new > OSTCBCurPtr->BasePrio) ? OSTCBCurPtr->BasePrio : prio_new; + if (prio_new > OSTCBCurPtr->Prio) { + OS_RdyListRemove(OSTCBCurPtr); + OSTCBCurPtr->Prio = prio_new; /* Lower owner's priority back to its original one */ + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(OSTCBCurPtr, prio_new); + OS_PrioInsert(prio_new); + OS_RdyListInsertTail(OSTCBCurPtr); /* Insert owner in ready list at new priority */ + OSPrioCur = prio_new; + } + } + /* Get TCB from head of pend list */ + p_tcb = p_pend_list->HeadPtr; + p_mutex->OwnerTCBPtr = p_tcb; /* Give mutex to new owner */ + p_mutex->OwnerNestingCtr = 1u; + OS_MutexGrpAdd(p_tcb, p_mutex); + /* Post to mutex */ + OS_Post((OS_PEND_OBJ *)((void *)p_mutex), + p_tcb, + (void *)0, + 0u, + ts); + + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + OS_TRACE_MUTEX_POST_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* CLEAR THE CONTENTS OF A MUTEX +* +* Description: This function is called by OSMutexDel() to clear the contents of a mutex +* + +* Argument(s): p_mutex is a pointer to the mutex to clear +* ------- +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_MutexClr (OS_MUTEX *p_mutex) +{ +#if (OS_OBJ_TYPE_REQ > 0u) + p_mutex->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_mutex->NamePtr = (CPU_CHAR *)((void *)"?MUTEX"); +#endif + p_mutex->MutexGrpNextPtr = (OS_MUTEX *)0; + p_mutex->OwnerTCBPtr = (OS_TCB *)0; + p_mutex->OwnerNestingCtr = 0u; +#if (OS_CFG_TS_EN > 0u) + p_mutex->TS = 0u; +#endif + OS_PendListInit(&p_mutex->PendList); /* Initialize the waiting list */ +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE MUTEX TO/FROM DEBUG LIST +* +* Description: These functions are called by uC/OS-III to add or remove a mutex to/from the debug list. +* +* Arguments : p_mutex is a pointer to the mutex to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_MutexDbgListAdd (OS_MUTEX *p_mutex) +{ + p_mutex->DbgNamePtr = (CPU_CHAR *)((void *)" "); + p_mutex->DbgPrevPtr = (OS_MUTEX *)0; + if (OSMutexDbgListPtr == (OS_MUTEX *)0) { + p_mutex->DbgNextPtr = (OS_MUTEX *)0; + } else { + p_mutex->DbgNextPtr = OSMutexDbgListPtr; + OSMutexDbgListPtr->DbgPrevPtr = p_mutex; + } + OSMutexDbgListPtr = p_mutex; +} + + +void OS_MutexDbgListRemove (OS_MUTEX *p_mutex) +{ + OS_MUTEX *p_mutex_next; + OS_MUTEX *p_mutex_prev; + + + p_mutex_prev = p_mutex->DbgPrevPtr; + p_mutex_next = p_mutex->DbgNextPtr; + + if (p_mutex_prev == (OS_MUTEX *)0) { + OSMutexDbgListPtr = p_mutex_next; + if (p_mutex_next != (OS_MUTEX *)0) { + p_mutex_next->DbgPrevPtr = (OS_MUTEX *)0; + } + p_mutex->DbgNextPtr = (OS_MUTEX *)0; + + } else if (p_mutex_next == (OS_MUTEX *)0) { + p_mutex_prev->DbgNextPtr = (OS_MUTEX *)0; + p_mutex->DbgPrevPtr = (OS_MUTEX *)0; + + } else { + p_mutex_prev->DbgNextPtr = p_mutex_next; + p_mutex_next->DbgPrevPtr = p_mutex_prev; + p_mutex->DbgNextPtr = (OS_MUTEX *)0; + p_mutex->DbgPrevPtr = (OS_MUTEX *)0; + } +} +#endif + + +/* +************************************************************************************************************************ +* MUTEX GROUP ADD +* +* Description: This function is called by the kernel to add a mutex to a task's mutex group. +* + +* Argument(s): p_tcb is a pointer to the tcb of the task to give the mutex to. +* +* p_mutex is a point to the mutex to add to the group. +* +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MutexGrpAdd (OS_TCB *p_tcb, OS_MUTEX *p_mutex) +{ + p_mutex->MutexGrpNextPtr = p_tcb->MutexGrpHeadPtr; /* The mutex grp is not sorted add to head of list. */ + p_tcb->MutexGrpHeadPtr = p_mutex; +} + + +/* +************************************************************************************************************************ +* MUTEX GROUP REMOVE +* +* Description: This function is called by the kernel to remove a mutex to a task's mutex group. +* + +* Argument(s): p_tcb is a pointer to the tcb of the task to remove the mutex from. +* +* p_mutex is a point to the mutex to remove from the group. +* +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MutexGrpRemove (OS_TCB *p_tcb, OS_MUTEX *p_mutex) +{ + OS_MUTEX **pp_mutex; + + pp_mutex = &p_tcb->MutexGrpHeadPtr; + + while(*pp_mutex != p_mutex) { + pp_mutex = &(*pp_mutex)->MutexGrpNextPtr; + } + + *pp_mutex = (*pp_mutex)->MutexGrpNextPtr; +} + + +/* +************************************************************************************************************************ +* MUTEX FIND HIGHEST PENDING +* +* Description: This function is called by the kernel to find the highest task pending on any mutex from a group. +* + +* Argument(s): p_tcb is a pointer to the tcb of the task to process. +* +* +* Returns : Highest priority pending or OS_CFG_PRIO_MAX - 1u if none found. +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +OS_PRIO OS_MutexGrpPrioFindHighest (OS_TCB *p_tcb) +{ + OS_MUTEX **pp_mutex; + OS_PRIO highest_prio; + OS_PRIO prio; + OS_TCB *p_head; + + + highest_prio = (OS_PRIO)(OS_CFG_PRIO_MAX - 1u); + pp_mutex = &p_tcb->MutexGrpHeadPtr; + + while(*pp_mutex != (OS_MUTEX *)0) { + p_head = (*pp_mutex)->PendList.HeadPtr; + if (p_head != (OS_TCB *)0) { + prio = p_head->Prio; + if(prio < highest_prio) { + highest_prio = prio; + } + } + pp_mutex = &(*pp_mutex)->MutexGrpNextPtr; + } + + return (highest_prio); +} + + +/* +************************************************************************************************************************ +* MUTEX GROUP POST ALL +* +* Description: This function is called by the kernel to post (release) all the mutex from a group. Used when deleting +* a task. +* + +* Argument(s): p_tcb is a pointer to the tcb of the task to process. +* +* +* Returns : none. +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_MutexGrpPostAll (OS_TCB *p_tcb) +{ + OS_MUTEX *p_mutex; + OS_MUTEX *p_mutex_next; + CPU_TS ts; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb_new; + + + p_mutex = p_tcb->MutexGrpHeadPtr; + + while(p_mutex != (OS_MUTEX *)0) { + + OS_TRACE_MUTEX_POST(p_mutex); + + p_mutex_next = p_mutex->MutexGrpNextPtr; +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ + p_mutex->TS = ts; +#else + ts = 0u; +#endif + OS_MutexGrpRemove(p_tcb, p_mutex); /* Remove mutex from owner's group */ + + p_pend_list = &p_mutex->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */ + p_mutex->OwnerNestingCtr = 0u; /* Decrement owner's nesting counter */ + p_mutex->OwnerTCBPtr = (OS_TCB *)0; /* No */ + } else { + /* Get TCB from head of pend list */ + p_tcb_new = p_pend_list->HeadPtr; + p_mutex->OwnerTCBPtr = p_tcb; /* Give mutex to new owner */ + p_mutex->OwnerNestingCtr = 1u; + OS_MutexGrpAdd(p_tcb_new, p_mutex); + /* Post to mutex */ + OS_Post((OS_PEND_OBJ *)((void *)p_mutex), + p_tcb_new, + (void *)0, + 0u, + ts); + } + + p_mutex = p_mutex_next; + } + +} + +#endif /* OS_CFG_MUTEX_EN */ diff --git a/rtos/uC-OS3/Source/os_prio.c b/rtos/uC-OS3/Source/os_prio.c new file mode 100644 index 00000000..2a637c71 --- /dev/null +++ b/rtos/uC-OS3/Source/os_prio.c @@ -0,0 +1,183 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* PRIORITY MANAGEMENT +* +* File : os_prio.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_prio__c = "$Id: $"; +#endif + + +/* +************************************************************************************************************************ +* INITIALIZE THE PRIORITY LIST +* +* Description: This function is called by uC/OS-III to initialize the list of ready priorities. +* +* Arguments : none +* +* Returns : none +* +* Note : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_PrioInit (void) +{ + CPU_DATA i; + + + /* Clear the bitmap table ... no task is ready */ + for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) { + OSPrioTbl[i] = 0u; + } + +#if (OS_CFG_TASK_IDLE_EN == 0u) + OS_PrioInsert ((OS_PRIO)(OS_CFG_PRIO_MAX - 1u)); /* Insert what would be the idle task */ +#endif +} + +/* +************************************************************************************************************************ +* GET HIGHEST PRIORITY TASK WAITING +* +* Description: This function is called by other uC/OS-III services to determine the highest priority task +* waiting on the event. +* +* Arguments : none +* +* Returns : The priority of the Highest Priority Task (HPT) waiting for the event +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +OS_PRIO OS_PrioGetHighest (void) +{ +#if (OS_CFG_PRIO_MAX <= (CPU_CFG_DATA_SIZE * 8u)) /* Optimize for less than word size nbr of priorities */ + return ((OS_PRIO)CPU_CntLeadZeros(OSPrioTbl[0])); + + +#elif (OS_CFG_PRIO_MAX <= (2u * (CPU_CFG_DATA_SIZE * 8u))) /* Optimize for 2x the word size nbr of priorities */ + if (OSPrioTbl[0] == 0u) { + return ((OS_PRIO)((OS_PRIO)CPU_CntLeadZeros(OSPrioTbl[1]) + (CPU_CFG_DATA_SIZE * 8u))); + } else { + return ((OS_PRIO)((OS_PRIO)CPU_CntLeadZeros(OSPrioTbl[0]))); + } + + +#else + CPU_DATA *p_tbl; + OS_PRIO prio; + + + prio = 0u; + p_tbl = &OSPrioTbl[0]; + while (*p_tbl == 0u) { /* Search the bitmap table for the highest priority */ + prio = (OS_PRIO)(prio + (CPU_CFG_DATA_SIZE * 8u)); /* Compute the step of each CPU_DATA entry */ + p_tbl++; + } + prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); /* Find the position of the first bit set at the entry */ + + return (prio); +#endif +} + +/* +************************************************************************************************************************ +* INSERT PRIORITY +* +* Description: This function is called to insert a priority in the priority table. +* +* Arguments : prio is the priority to insert +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_PrioInsert (OS_PRIO prio) +{ +#if (OS_CFG_PRIO_MAX <= (CPU_CFG_DATA_SIZE * 8u)) /* Optimize for less than word size nbr of priorities */ + OSPrioTbl[0] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio); + + +#elif (OS_CFG_PRIO_MAX <= (2u * (CPU_CFG_DATA_SIZE * 8u))) /* Optimize for 2x the word size nbr of priorities */ + if (prio < (CPU_CFG_DATA_SIZE * 8u)) { + OSPrioTbl[0] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio); + } else { + OSPrioTbl[1] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - (prio - (CPU_CFG_DATA_SIZE * 8u))); + } + + +#else + CPU_DATA bit_nbr; + OS_PRIO ix; + + ix = (OS_PRIO)(prio / (CPU_CFG_DATA_SIZE * 8u)); + bit_nbr = (CPU_DATA)prio & ((CPU_CFG_DATA_SIZE * 8u) - 1u); + OSPrioTbl[ix] |= (CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - bit_nbr); +#endif +} + +/* +************************************************************************************************************************ +* REMOVE PRIORITY +* +* Description: This function is called to remove a priority in the priority table. +* +* Arguments : prio is the priority to remove +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_PrioRemove (OS_PRIO prio) +{ +#if (OS_CFG_PRIO_MAX <= (CPU_CFG_DATA_SIZE * 8u)) /* Optimize for less than word size nbr of priorities */ + OSPrioTbl[0] &= ~((CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio)); + + +#elif (OS_CFG_PRIO_MAX <= (2u * (CPU_CFG_DATA_SIZE * 8u))) /* Optimize for 2x the word size nbr of priorities */ + if (prio < (CPU_CFG_DATA_SIZE * 8u)) { + OSPrioTbl[0] &= ~((CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - prio)); + } else { + OSPrioTbl[1] &= ~((CPU_DATA)1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - (prio - (CPU_CFG_DATA_SIZE * 8u)))); + } + + +#else + CPU_DATA bit_nbr; + OS_PRIO ix; + + ix = (OS_PRIO)(prio / (CPU_CFG_DATA_SIZE * 8u)); + bit_nbr = (CPU_DATA)prio & ((CPU_CFG_DATA_SIZE * 8u) - 1u); + OSPrioTbl[ix] &= ~((CPU_DATA) 1u << (((CPU_CFG_DATA_SIZE * 8u) - 1u) - bit_nbr)); +#endif +} diff --git a/rtos/uC-OS3/Source/os_q.c b/rtos/uC-OS3/Source/os_q.c new file mode 100644 index 00000000..0dab280d --- /dev/null +++ b/rtos/uC-OS3/Source/os_q.c @@ -0,0 +1,987 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* MESSAGE QUEUE MANAGEMENT +* +* File : os_q.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_q__c = "$Id: $"; +#endif + + +#if (OS_CFG_Q_EN > 0u) +/* +************************************************************************************************************************ +* CREATE A MESSAGE QUEUE +* +* Description: This function is called by your application to create a message queue. Message queues MUST be created +* before they can be used. +* +* Arguments : p_q is a pointer to the message queue +* +* p_name is a pointer to an ASCII string that will be used to name the message queue +* +* max_qty indicates the maximum size of the message queue (must be non-zero). Note that it's also not +* possible to have a size higher than the maximum number of OS_MSGs available. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful +* OS_ERR_CREATE_ISR Can't create from an ISR +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the Queue after you called +* OSSafetyCriticalStart() +* OS_ERR_OBJ_PTR_NULL If you passed a NULL pointer for 'p_q' +* OS_ERR_Q_SIZE If the size you specified is 0 +* OS_ERR_OBJ_CREATED If the message queue was already created +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSQCreate (OS_Q *p_q, + CPU_CHAR *p_name, + OS_MSG_QTY max_qty, + OS_ERR *p_err) + +{ + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to be called from an ISR */ + *p_err = OS_ERR_CREATE_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate arguments */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } + if (max_qty == 0u) { /* Cannot specify a zero size queue */ + *p_err = OS_ERR_Q_SIZE; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_q->Type == OS_OBJ_TYPE_Q) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_q->Type = OS_OBJ_TYPE_Q; /* Mark the data structure as a message queue */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_q->NamePtr = p_name; +#else + (void)p_name; +#endif + OS_MsgQInit(&p_q->MsgQ, /* Initialize the queue */ + max_qty); + OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */ + +#if (OS_CFG_DBG_EN > 0u) + OS_QDbgListAdd(p_q); + OSQQty++; /* One more queue created */ +#endif + OS_TRACE_Q_CREATE(p_q, p_name); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DELETE A MESSAGE QUEUE +* +* Description: This function deletes a message queue and readies all tasks pending on the queue. +* +* Arguments : p_q is a pointer to the message queue you want to delete +* +* opt determines delete options as follows: +* +* OS_OPT_DEL_NO_PEND Delete the queue ONLY if no task pending +* OS_OPT_DEL_ALWAYS Deletes the queue even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the queue was deleted +* OS_ERR_DEL_ISR If you tried to delete the queue from an ISR +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the message queue after you +* called OSStart() +* OS_ERR_OBJ_PTR_NULL If you pass a NULL pointer for 'p_q' +* OS_ERR_OBJ_TYPE If the message queue was not created +* OS_ERR_OPT_INVALID An invalid option was specified +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TASK_WAITING One or more tasks were waiting on the queue +* +* Returns : == 0 if no tasks were waiting on the queue, or upon error. +* > 0 if one or more tasks waiting on the queue are now readied and informed. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the queue MUST +* check the return code of OSQPend(). +* +* 2) Because ALL tasks pending on the queue will be readied, you MUST be careful in applications where the +* queue is used for mutual exclusion because the resource(s) will no longer be guarded by the queue. +************************************************************************************************************************ +*/ + +#if (OS_CFG_Q_DEL_EN > 0u) +OS_OBJ_QTY OSQDel (OS_Q *p_q, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_OBJ_QTY nbr_tasks; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_Q_DEL_ENTER(p_q, opt); + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_TRACE_Q_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME); + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't delete a message queue from an ISR */ + OS_TRACE_Q_DEL_EXIT(OS_ERR_DEL_ISR); + *p_err = OS_ERR_DEL_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_Q_DEL_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate 'p_q' */ + OS_TRACE_Q_DEL_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */ + OS_TRACE_Q_DEL_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_q->PendList; + nbr_tasks = 0u; + switch (opt) { + case OS_OPT_DEL_NO_PEND: /* Delete message queue only if no task waiting */ + if (p_pend_list->HeadPtr == (OS_TCB *)0) { +#if (OS_CFG_DBG_EN > 0u) + OS_QDbgListRemove(p_q); + OSQQty--; +#endif + OS_TRACE_Q_DEL(p_q); + OS_QClr(p_q); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + } else { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_WAITING; + } + break; + + case OS_OPT_DEL_ALWAYS: /* Always delete the message queue */ +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* Remove all tasks from the pend list */ + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_DEL); + nbr_tasks++; + } +#if (OS_CFG_DBG_EN > 0u) + OS_QDbgListRemove(p_q); + OSQQty--; +#endif + OS_TRACE_Q_DEL(p_q); + OS_QClr(p_q); + CPU_CRITICAL_EXIT(); + OSSched(); /* Find highest priority task ready to run */ + *p_err = OS_ERR_NONE; + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OPT_INVALID; + break; + } + OS_TRACE_Q_DEL_EXIT(*p_err); + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* FLUSH QUEUE +* +* Description : This function is used to flush the contents of the message queue. +* +* Arguments : p_q is a pointer to the message queue to flush +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE Upon success +* OS_ERR_FLUSH_ISR If you called this function from an ISR +* OS_ERR_OBJ_PTR_NULL If you passed a NULL pointer for 'p_q' +* OS_ERR_OBJ_TYPE If you didn't create the message queue +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* +* Returns : == 0 if no entries were freed, or upon error. +* > 0 the number of freed entries. +* +* Note(s) : 1) You should use this function with great care because, when to flush the queue, you LOOSE the +* references to what the queue entries are pointing to and thus, you could cause 'memory leaks'. In +* other words, the data you are pointing to that's being referenced by the queue entries should, most +* likely, need to be de-allocated (i.e. freed). +************************************************************************************************************************ +*/ + +#if (OS_CFG_Q_FLUSH_EN > 0u) +OS_MSG_QTY OSQFlush (OS_Q *p_q, + OS_ERR *p_err) +{ + OS_MSG_QTY entries; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't flush a message queue from an ISR */ + *p_err = OS_ERR_FLUSH_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate arguments */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + entries = OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the OS_MSG pool */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (entries); +} +#endif + + +/* +************************************************************************************************************************ +* PEND ON A QUEUE FOR A MESSAGE +* +* Description: This function waits for a message to be sent to a queue. +* +* Arguments : p_q is a pointer to the message queue +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a +* message to arrive at the queue up to the amount of time specified by this argument. If you +* specify 0, however, your task will wait forever at the specified queue or, until a message +* arrives. +* +* opt determines whether the user wants to block if the queue is empty or not: +* +* OS_OPT_PEND_BLOCKING +* OS_OPT_PEND_NON_BLOCKING +* +* p_msg_size is a pointer to a variable that will receive the size of the message +* +* p_ts is a pointer to a variable that will receive the timestamp of when the message was +* received, pend aborted or the message queue deleted, If you pass a NULL pointer (i.e. +* (CPU_TS *)0) then you will not get the timestamp. In other words, passing a NULL pointer +* is valid and indicates that you don't need the timestamp. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and your task received a message +* OS_ERR_OBJ_DEL If 'p_q' was deleted +* OS_ERR_OBJ_PTR_NULL If you pass a NULL pointer for 'p_q' +* OS_ERR_OBJ_TYPE If the message queue was not created +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT The pend was aborted +* OS_ERR_PEND_ISR If you called this function from an ISR +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the queue was not empty +* OS_ERR_PTR_INVALID If you passed a NULL pointer of 'p_msg_size' +* OS_ERR_SCHED_LOCKED The scheduler is locked +* OS_ERR_STATUS_INVALID If the pend status has an invalid value +* OS_ERR_TIMEOUT A message was not received within the specified timeout +* would lead to a suspension. +* OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified +* +* Returns : != (void *)0 is a pointer to the message received +* == (void *)0 if you received a NULL pointer message or, +* if no message was received or, +* if 'p_q' is a NULL pointer or, +* if you didn't pass a pointer to a queue. +* +* Note(s) : This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +void *OSQPend (OS_Q *p_q, + OS_TICK timeout, + OS_OPT opt, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + void *p_void; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + + OS_TRACE_Q_PEND_ENTER(p_q, timeout, opt, p_msg_size, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + *p_err = OS_ERR_TICK_DISABLED; + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_TICK_DISABLED); + return ((void *)0); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != OS_OPT_PEND_NON_BLOCKING) { + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_PEND_ISR); + *p_err = OS_ERR_PEND_ISR; + return ((void *)0); + } + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_Q_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return ((void *)0); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate arguments */ + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return ((void *)0); + } + if (p_msg_size == (OS_MSG_SIZE *)0) { + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_PTR_INVALID); + *p_err = OS_ERR_PTR_INVALID; + return ((void *)0); + } + switch (opt) { + case OS_OPT_PEND_BLOCKING: + case OS_OPT_PEND_NON_BLOCKING: + break; + + default: + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return ((void *)0); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */ + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return ((void *)0); + } +#endif + + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; /* Initialize the returned timestamp */ + } + + CPU_CRITICAL_ENTER(); + p_void = OS_MsgQGet(&p_q->MsgQ, /* Any message waiting in the message queue? */ + p_msg_size, + p_ts, + p_err); + if (*p_err == OS_ERR_NONE) { + OS_TRACE_Q_PEND(p_q); + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_PEND_EXIT(OS_ERR_NONE); + return (p_void); /* Yes, Return message received */ + } + + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */ + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */ + return ((void *)0); + } else { + if (OSSchedLockNestingCtr > 0u) { /* Can't pend when the scheduler is locked */ + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_PEND_FAILED(p_q); + OS_TRACE_Q_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; + return ((void *)0); + } + } + + OS_Pend((OS_PEND_OBJ *)((void *)p_q), /* Block task pending on Message Queue */ + OSTCBCurPtr, + OS_TASK_PEND_ON_Q, + timeout); + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_PEND_BLOCK(p_q); + OSSched(); /* Find the next highest priority task ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { + case OS_STATUS_PEND_OK: /* Extract message from TCB (Put there by Post) */ + p_void = OSTCBCurPtr->MsgPtr; + *p_msg_size = OSTCBCurPtr->MsgSize; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_Q_PEND(p_q); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ + p_void = (void *)0; + *p_msg_size = 0u; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_Q_PEND_FAILED(p_q); + *p_err = OS_ERR_PEND_ABORT; + break; + + case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get event within TO */ + p_void = (void *)0; + *p_msg_size = 0u; + OS_TRACE_Q_PEND_FAILED(p_q); + *p_err = OS_ERR_TIMEOUT; + break; + + case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ + p_void = (void *)0; + *p_msg_size = 0u; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_Q_PEND_FAILED(p_q); + *p_err = OS_ERR_OBJ_DEL; + break; + + default: + p_void = (void *)0; + *p_msg_size = 0u; + OS_TRACE_Q_PEND_FAILED(p_q); + *p_err = OS_ERR_STATUS_INVALID; + break; + } + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_PEND_EXIT(*p_err); + return (p_void); +} + + +/* +************************************************************************************************************************ +* ABORT WAITING ON A MESSAGE QUEUE +* +* Description: This function aborts & readies any tasks currently waiting on a queue. This function should be used to +* fault-abort the wait on the queue, rather than to normally signal the queue via OSQPost(). +* +* Arguments : p_q is a pointer to the message queue +* +* opt determines the type of ABORT performed: +* +* OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the queue +* OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the queue +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE At least one task waiting on the queue was readied and +* informed of the aborted wait; check return value for the +* number of tasks whose wait on the queue was aborted +* OS_ERR_OBJ_PTR_NULL If you pass a NULL pointer for 'p_q' +* OS_ERR_OBJ_TYPE If the message queue was not created +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If this function was called from an ISR +* OS_ERR_PEND_ABORT_NONE No task were pending +* +* Returns : == 0 if no tasks were waiting on the queue, or upon error. +* > 0 if one or more tasks waiting on the queue are now readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_Q_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSQPendAbort (OS_Q *p_q, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + OS_OBJ_QTY nbr_tasks; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to Pend Abort from an ISR */ + *p_err = OS_ERR_PEND_ABORT_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate 'p_q' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_ABORT_1: + case OS_OPT_PEND_ABORT_ALL: + case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED: + case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure queue was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_q->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on queue? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_PEND_ABORT_NONE; + return (0u); + } + + nbr_tasks = 0u; +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_ABORT); + nbr_tasks++; + if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */ + break; /* No */ + } + } + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + + *p_err = OS_ERR_NONE; + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* POST MESSAGE TO A QUEUE +* +* Description: This function sends a message to a queue. With the 'opt' argument, you can specify whether the message +* is broadcast to all waiting tasks and/or whether you post the message to the front of the queue (LIFO) +* or normally (FIFO) at the end of the queue. +* +* Arguments : p_q is a pointer to a message queue that must have been created by OSQCreate(). +* +* p_void is a pointer to the message to send. +* +* msg_size specifies the size of the message (in bytes) +* +* opt determines the type of POST performed: +* +* OS_OPT_POST_ALL POST to ALL tasks that are waiting on the queue. This option +* can be added to either OS_OPT_POST_FIFO or OS_OPT_POST_LIFO +* OS_OPT_POST_FIFO POST message to end of queue (FIFO) and wake up a single +* waiting task. +* OS_OPT_POST_LIFO POST message to the front of the queue (LIFO) and wake up +* a single waiting task. +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* Note(s): 1) OS_OPT_POST_NO_SCHED can be added (or OR'd) with one of the other options. +* 2) OS_OPT_POST_ALL can be added (or OR'd) with one of the other options. +* 3) Possible combination of options are: +* +* OS_OPT_POST_FIFO +* OS_OPT_POST_LIFO +* OS_OPT_POST_FIFO + OS_OPT_POST_ALL +* OS_OPT_POST_LIFO + OS_OPT_POST_ALL +* OS_OPT_POST_FIFO + OS_OPT_POST_NO_SCHED +* OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED +* OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED +* OS_OPT_POST_LIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs to use to place the message into +* OS_ERR_OBJ_PTR_NULL If 'p_q' is a NULL pointer +* OS_ERR_OBJ_TYPE If the message queue was not initialized +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_Q_MAX If the queue is full +* +* Returns : None +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSQPost (OS_Q *p_q, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_OPT post_type; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + OS_TCB *p_tcb_next; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OS_TRACE_Q_POST_ENTER(p_q, p_void, msg_size, opt); + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_Q_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_q == (OS_Q *)0) { /* Validate 'p_q' */ + OS_TRACE_Q_POST_FAILED(p_q); + OS_TRACE_Q_POST_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_POST_FIFO: + case OS_OPT_POST_LIFO: + case OS_OPT_POST_FIFO | OS_OPT_POST_ALL: + case OS_OPT_POST_LIFO | OS_OPT_POST_ALL: + case OS_OPT_POST_FIFO | OS_OPT_POST_NO_SCHED: + case OS_OPT_POST_LIFO | OS_OPT_POST_NO_SCHED: + case OS_OPT_POST_FIFO | (OS_OPT)(OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED): + case OS_OPT_POST_LIFO | (OS_OPT)(OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED): + break; + + default: + OS_TRACE_Q_POST_FAILED(p_q); + OS_TRACE_Q_POST_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_q->Type != OS_OBJ_TYPE_Q) { /* Make sure message queue was created */ + OS_TRACE_Q_POST_FAILED(p_q); + OS_TRACE_Q_POST_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + + OS_TRACE_Q_POST(p_q); + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_q->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on message queue? */ + if ((opt & OS_OPT_POST_LIFO) == 0u) { /* Determine whether we post FIFO or LIFO */ + post_type = OS_OPT_POST_FIFO; + } else { + post_type = OS_OPT_POST_LIFO; + } + OS_MsgQPut(&p_q->MsgQ, /* Place message in the message queue */ + p_void, + msg_size, + post_type, + ts, + p_err); + CPU_CRITICAL_EXIT(); + OS_TRACE_Q_POST_EXIT(*p_err); + return; + } + + p_tcb = p_pend_list->HeadPtr; + while (p_tcb != (OS_TCB *)0) { + p_tcb_next = p_tcb->PendNextPtr; + OS_Post((OS_PEND_OBJ *)((void *)p_q), + p_tcb, + p_void, + msg_size, + ts); + if ((opt & OS_OPT_POST_ALL) == 0u) { /* Post message to all tasks waiting? */ + break; /* No */ + } + p_tcb = p_tcb_next; + } + + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + + *p_err = OS_ERR_NONE; + OS_TRACE_Q_POST_EXIT(*p_err); +} + + +/* +************************************************************************************************************************ +* CLEAR THE CONTENTS OF A MESSAGE QUEUE +* +* Description: This function is called by OSQDel() to clear the contents of a message queue +* + +* Argument(s): p_q is a pointer to the queue to clear +* --- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_QClr (OS_Q *p_q) +{ + (void)OS_MsgQFreeAll(&p_q->MsgQ); /* Return all OS_MSGs to the free list */ +#if (OS_OBJ_TYPE_REQ > 0u) + p_q->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_q->NamePtr = (CPU_CHAR *)((void *)"?Q"); +#endif + OS_MsgQInit(&p_q->MsgQ, /* Initialize the list of OS_MSGs */ + 0u); + OS_PendListInit(&p_q->PendList); /* Initialize the waiting list */ +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE MESSAGE QUEUE TO/FROM DEBUG LIST +* +* Description: These functions are called by uC/OS-III to add or remove a message queue to/from a message queue debug +* list. +* +* Arguments : p_q is a pointer to the message queue to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_QDbgListAdd (OS_Q *p_q) +{ + p_q->DbgNamePtr = (CPU_CHAR *)((void *)" "); + p_q->DbgPrevPtr = (OS_Q *)0; + if (OSQDbgListPtr == (OS_Q *)0) { + p_q->DbgNextPtr = (OS_Q *)0; + } else { + p_q->DbgNextPtr = OSQDbgListPtr; + OSQDbgListPtr->DbgPrevPtr = p_q; + } + OSQDbgListPtr = p_q; +} + + +void OS_QDbgListRemove (OS_Q *p_q) +{ + OS_Q *p_q_next; + OS_Q *p_q_prev; + + + p_q_prev = p_q->DbgPrevPtr; + p_q_next = p_q->DbgNextPtr; + + if (p_q_prev == (OS_Q *)0) { + OSQDbgListPtr = p_q_next; + if (p_q_next != (OS_Q *)0) { + p_q_next->DbgPrevPtr = (OS_Q *)0; + } + p_q->DbgNextPtr = (OS_Q *)0; + + } else if (p_q_next == (OS_Q *)0) { + p_q_prev->DbgNextPtr = (OS_Q *)0; + p_q->DbgPrevPtr = (OS_Q *)0; + + } else { + p_q_prev->DbgNextPtr = p_q_next; + p_q_next->DbgPrevPtr = p_q_prev; + p_q->DbgNextPtr = (OS_Q *)0; + p_q->DbgPrevPtr = (OS_Q *)0; + } +} +#endif +#endif diff --git a/rtos/uC-OS3/Source/os_sem.c b/rtos/uC-OS3/Source/os_sem.c new file mode 100644 index 00000000..deec2bf4 --- /dev/null +++ b/rtos/uC-OS3/Source/os_sem.c @@ -0,0 +1,966 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* SEMAPHORE MANAGEMENT +* +* File : os_sem.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_sem__c = "$Id: $"; +#endif + + +#if (OS_CFG_SEM_EN > 0u) +/* +************************************************************************************************************************ +* CREATE A SEMAPHORE +* +* Description: This function creates a semaphore. +* +* Arguments : p_sem is a pointer to the semaphore to initialize. Your application is responsible for +* allocating storage for the semaphore. +* +* p_name is a pointer to the name you would like to give the semaphore. +* +* cnt is the initial value for the semaphore. +* If used to share resources, you should initialize to the number of resources available. +* If used to signal the occurrence of event(s) then you should initialize to 0. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE If the call was successful +* OS_ERR_CREATE_ISR If you called this function from an ISR +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the semaphore after you +* called OSSafetyCriticalStart() +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer +* OS_ERR_OBJ_CREATED If the semaphore was already created +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSSemCreate (OS_SEM *p_sem, + CPU_CHAR *p_name, + OS_SEM_CTR cnt, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to be called from an ISR */ + *p_err = OS_ERR_CREATE_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_sem->Type == OS_OBJ_TYPE_SEM) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_sem->Type = OS_OBJ_TYPE_SEM; /* Mark the data structure as a semaphore */ +#endif + p_sem->Ctr = cnt; /* Set semaphore value */ +#if (OS_CFG_TS_EN > 0u) + p_sem->TS = 0u; +#endif +#if (OS_CFG_DBG_EN > 0u) + p_sem->NamePtr = p_name; /* Save the name of the semaphore */ +#else + (void)p_name; +#endif + OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */ + +#if (OS_CFG_DBG_EN > 0u) + OS_SemDbgListAdd(p_sem); + OSSemQty++; +#endif + + OS_TRACE_SEM_CREATE(p_sem, p_name); + + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DELETE A SEMAPHORE +* +* Description: This function deletes a semaphore. +* +* Arguments : p_sem is a pointer to the semaphore to delete +* +* opt determines delete options as follows: +* +* OS_OPT_DEL_NO_PEND Delete semaphore ONLY if no task pending +* OS_OPT_DEL_ALWAYS Deletes the semaphore even if tasks are waiting. +* In this case, all the tasks pending will be readied. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the semaphore was deleted +* OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the semaphore after you called +* OSStart() +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore +* OS_ERR_OPT_INVALID An invalid option was specified +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore +* +* Returns : == 0 if no tasks were waiting on the semaphore, or upon error. +* > 0 if one or more tasks waiting on the semaphore are now readied and informed. +* +* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the semaphore +* MUST check the return code of OSSemPend(). +* 2) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in applications where +* the semaphore is used for mutual exclusion because the resource(s) will no longer be guarded by the +* semaphore. +************************************************************************************************************************ +*/ + +#if (OS_CFG_SEM_DEL_EN > 0u) +OS_OBJ_QTY OSSemDel (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_OBJ_QTY nbr_tasks; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_SEM_DEL_ENTER(p_sem, opt); + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + OS_TRACE_SEM_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME); + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to delete a semaphore from an ISR */ + OS_TRACE_SEM_DEL_EXIT(OS_ERR_DEL_ISR); + *p_err = OS_ERR_DEL_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_SEM_DEL_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ + OS_TRACE_SEM_DEL_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_sem->PendList; + nbr_tasks = 0u; + switch (opt) { + case OS_OPT_DEL_NO_PEND: /* Delete semaphore only if no task waiting */ + if (p_pend_list->HeadPtr == (OS_TCB *)0) { +#if (OS_CFG_DBG_EN > 0u) + OS_SemDbgListRemove(p_sem); + OSSemQty--; +#endif + OS_TRACE_SEM_DEL(p_sem); + OS_SemClr(p_sem); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + } else { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_WAITING; + } + break; + + case OS_OPT_DEL_ALWAYS: /* Always delete the semaphore */ +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* Remove all tasks on the pend list */ + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_DEL); + nbr_tasks++; + } +#if (OS_CFG_DBG_EN > 0u) + OS_SemDbgListRemove(p_sem); + OSSemQty--; +#endif + OS_TRACE_SEM_DEL(p_sem); + OS_SemClr(p_sem); + CPU_CRITICAL_EXIT(); + OSSched(); /* Find highest priority task ready to run */ + *p_err = OS_ERR_NONE; + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OPT_INVALID; + break; + } + + OS_TRACE_SEM_DEL_EXIT(*p_err); + + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* PEND ON SEMAPHORE +* +* Description: This function waits for a semaphore. +* +* Arguments : p_sem is a pointer to the semaphore +* +* timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for the +* resource up to the amount of time (in 'ticks') specified by this argument. If you specify +* 0, however, your task will wait forever at the specified semaphore or, until the resource +* becomes available (or the event occurs). +* +* opt determines whether the user wants to block if the semaphore is available or not: +* +* OS_OPT_PEND_BLOCKING +* OS_OPT_PEND_NON_BLOCKING +* +* p_ts is a pointer to a variable that will receive the timestamp of when the semaphore was posted +* or pend aborted or the semaphore deleted. If you pass a NULL pointer (i.e. (CPU_TS*)0) +* then you will not get the timestamp. In other words, passing a NULL pointer is valid +* and indicates that you don't need the timestamp. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and your task owns the resource +* or, the event you are waiting for occurred +* OS_ERR_OBJ_DEL If 'p_sem' was deleted +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore +* OS_ERR_OPT_INVALID If you specified an invalid value for 'opt' +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT If the pend was aborted by another task +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* would lead to a suspension +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the semaphore was not +* available +* OS_ERR_SCHED_LOCKED If you called this function when the scheduler is locked +* OS_ERR_STATUS_INVALID Pend status is invalid +* OS_ERR_TIMEOUT The semaphore was not received within the specified +* timeout +* OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified +* +* +* Returns : The current value of the semaphore counter or 0 if not available. +* +* Note(s) : This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +OS_SEM_CTR OSSemPend (OS_SEM *p_sem, + OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + OS_SEM_CTR ctr; + CPU_SR_ALLOC(); + + +#if (OS_CFG_TS_EN == 0u) + (void)p_ts; /* Prevent compiler warning for not using 'ts' */ +#endif + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_SEM_PEND_ENTER(p_sem, timeout, opt, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + *p_err = OS_ERR_TICK_DISABLED; + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_TICK_DISABLED); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + if ((opt & OS_OPT_PEND_NON_BLOCKING) != OS_OPT_PEND_NON_BLOCKING) { + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_ISR); + *p_err = OS_ERR_PEND_ISR; + return (0u); + } + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_SEM_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_BLOCKING: + case OS_OPT_PEND_NON_BLOCKING: + break; + + default: + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + + CPU_CRITICAL_ENTER(); + if (p_sem->Ctr > 0u) { /* Resource available? */ + p_sem->Ctr--; /* Yes, caller may proceed */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = p_sem->TS; /* get timestamp of last post */ + } +#endif + ctr = p_sem->Ctr; + OS_TRACE_SEM_PEND(p_sem); + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (ctr); + } + + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + ctr = p_sem->Ctr; /* No */ + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; + return (ctr); + } else { /* Yes */ + if (OSSchedLockNestingCtr > 0u) { /* Can't pend when the scheduler is locked */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_FAILED(p_sem); + OS_TRACE_SEM_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; + return (0u); + } + } + + OS_Pend((OS_PEND_OBJ *)((void *)p_sem), /* Block task pending on Semaphore */ + OSTCBCurPtr, + OS_TASK_PEND_ON_SEM, + timeout); + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_BLOCK(p_sem); + OSSched(); /* Find the next highest priority task ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { + case OS_STATUS_PEND_OK: /* We got the semaphore */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_SEM_PEND(p_sem); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_SEM_PEND_FAILED(p_sem); + *p_err = OS_ERR_PEND_ABORT; + break; + + case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_SEM_PEND_FAILED(p_sem); + *p_err = OS_ERR_TIMEOUT; + break; + + case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_SEM_PEND_FAILED(p_sem); + *p_err = OS_ERR_OBJ_DEL; + break; + + default: + OS_TRACE_SEM_PEND_FAILED(p_sem); + *p_err = OS_ERR_STATUS_INVALID; + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_EXIT(*p_err); + return (0u); + } + ctr = p_sem->Ctr; + CPU_CRITICAL_EXIT(); + OS_TRACE_SEM_PEND_EXIT(*p_err); + return (ctr); +} + + +/* +************************************************************************************************************************ +* ABORT WAITING ON A SEMAPHORE +* +* Description: This function aborts & readies any tasks currently waiting on a semaphore. This function should be used +* to fault-abort the wait on the semaphore, rather than to normally signal the semaphore via OSSemPost(). +* +* Arguments : p_sem is a pointer to the semaphore +* +* opt determines the type of ABORT performed: +* +* OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the semaphore +* OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the semaphore +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE At least one task waiting on the semaphore was readied and +* informed of the aborted wait; check return value for the +* number of tasks whose wait on the semaphore was aborted. +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer. +* OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If you called this function from an ISR +* OS_ERR_PEND_ABORT_NONE No task were pending +* +* Returns : == 0 if no tasks were waiting on the semaphore, or upon error. +* > 0 if one or more tasks waiting on the semaphore are now readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_SEM_PEND_ABORT_EN > 0u) +OS_OBJ_QTY OSSemPendAbort (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + CPU_TS ts; + OS_OBJ_QTY nbr_tasks; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to Pend Abort from an ISR */ + *p_err = OS_ERR_PEND_ABORT_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_ABORT_1: + case OS_OPT_PEND_ABORT_ALL: + case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED: + case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + p_pend_list = &p_sem->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on semaphore? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_PEND_ABORT_NONE; + return (0u); + } + + nbr_tasks = 0u; +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */ +#else + ts = 0u; +#endif + while (p_pend_list->HeadPtr != (OS_TCB *)0) { + p_tcb = p_pend_list->HeadPtr; + OS_PendAbort(p_tcb, + ts, + OS_STATUS_PEND_ABORT); + nbr_tasks++; + if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */ + break; /* No */ + } + } + CPU_CRITICAL_EXIT(); + + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + + *p_err = OS_ERR_NONE; + return (nbr_tasks); +} +#endif + + +/* +************************************************************************************************************************ +* POST TO A SEMAPHORE +* +* Description: This function signals a semaphore. +* +* Arguments : p_sem is a pointer to the semaphore +* +* opt determines the type of POST performed: +* +* OS_OPT_POST_1 POST and ready only the highest priority task waiting on semaphore +* (if tasks are waiting). +* OS_OPT_POST_ALL POST to ALL tasks that are waiting on the semaphore +* +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the semaphore was signaled +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow +* +* Returns : The current value of the semaphore counter or 0 upon error. +* +* Note(s) : 1) OS_OPT_POST_NO_SCHED can be added with one of the other options. +************************************************************************************************************************ +*/ + +OS_SEM_CTR OSSemPost (OS_SEM *p_sem, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_SEM_CTR ctr; + OS_PEND_LIST *p_pend_list; + OS_TCB *p_tcb; + OS_TCB *p_tcb_next; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_SEM_POST_ENTER(p_sem, opt); + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_SEM_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + OS_TRACE_SEM_POST_FAILED(p_sem); + OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_PTR_NULL); + *p_err = OS_ERR_OBJ_PTR_NULL; + return (0u); + } + switch (opt) { /* Validate 'opt' */ + case OS_OPT_POST_1: + case OS_OPT_POST_ALL: + case OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED: + case OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED: + break; + + default: + OS_TRACE_SEM_POST_FAILED(p_sem); + OS_TRACE_SEM_POST_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ + OS_TRACE_SEM_POST_FAILED(p_sem); + OS_TRACE_SEM_POST_EXIT(OS_ERR_OBJ_TYPE); + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + + OS_TRACE_SEM_POST(p_sem); + CPU_CRITICAL_ENTER(); + p_pend_list = &p_sem->PendList; + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on semaphore? */ + if (p_sem->Ctr == (OS_SEM_CTR)-1) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_SEM_OVF; + OS_TRACE_SEM_POST_EXIT(*p_err); + return (0u); + } + p_sem->Ctr++; /* No */ + ctr = p_sem->Ctr; +#if (OS_CFG_TS_EN > 0u) + p_sem->TS = ts; /* Save timestamp in semaphore control block */ +#endif + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + OS_TRACE_SEM_POST_EXIT(*p_err); + return (ctr); + } + + p_tcb = p_pend_list->HeadPtr; + while (p_tcb != (OS_TCB *)0) { + p_tcb_next = p_tcb->PendNextPtr; + OS_Post((OS_PEND_OBJ *)((void *)p_sem), + p_tcb, + (void *)0, + 0u, + ts); + if ((opt & OS_OPT_POST_ALL) == 0u) { /* Post to all tasks waiting? */ + break; /* No */ + } + p_tcb = p_tcb_next; + } + CPU_CRITICAL_EXIT(); + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + *p_err = OS_ERR_NONE; + + OS_TRACE_SEM_POST_EXIT(*p_err); + return (0u); +} + + +/* +************************************************************************************************************************ +* SET SEMAPHORE +* +* Description: This function sets the semaphore count to the value specified as an argument. Typically, this value +* would be 0 but of course, we can set the semaphore to any value. +* +* You would typically use this function when a semaphore is used as a signaling mechanism +* and, you want to reset the count value. +* +* Arguments : p_sem is a pointer to the semaphore +* +* cnt is the new value for the semaphore count. You would pass 0 to reset the semaphore count. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successful and the semaphore value was set +* OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer +* OS_ERR_OBJ_TYPE If 'p_sem' is not pointing to a semaphore +* OS_ERR_SET_ISR If called from an ISR +* OS_ERR_TASK_WAITING If tasks are waiting on the semaphore +* +* Returns : None +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_SEM_SET_EN > 0u) +void OSSemSet (OS_SEM *p_sem, + OS_SEM_CTR cnt, + OS_ERR *p_err) +{ + OS_PEND_LIST *p_pend_list; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't call this function from an ISR */ + *p_err = OS_ERR_SET_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */ + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif + + *p_err = OS_ERR_NONE; + CPU_CRITICAL_ENTER(); + if (p_sem->Ctr > 0u) { /* See if semaphore already has a count */ + p_sem->Ctr = cnt; /* Yes, set it to the new value specified. */ + } else { + p_pend_list = &p_sem->PendList; /* No */ + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* See if task(s) waiting? */ + p_sem->Ctr = cnt; /* No, OK to set the value */ + } else { + *p_err = OS_ERR_TASK_WAITING; + } + } + CPU_CRITICAL_EXIT(); +} +#endif + + +/* +************************************************************************************************************************ +* CLEAR THE CONTENTS OF A SEMAPHORE +* +* Description: This function is called by OSSemDel() to clear the contents of a semaphore +* + +* Argument(s): p_sem is a pointer to the semaphore to clear +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_SemClr (OS_SEM *p_sem) +{ +#if (OS_OBJ_TYPE_REQ > 0u) + p_sem->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */ +#endif + p_sem->Ctr = 0u; /* Set semaphore value */ +#if (OS_CFG_TS_EN > 0u) + p_sem->TS = 0u; /* Clear the time stamp */ +#endif +#if (OS_CFG_DBG_EN > 0u) + p_sem->NamePtr = (CPU_CHAR *)((void *)"?SEM"); +#endif + OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */ +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE SEMAPHORE TO/FROM DEBUG LIST +* +* Description: These functions are called by uC/OS-III to add or remove a semaphore to/from the debug list. +* +* Arguments : p_sem is a pointer to the semaphore to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_SemDbgListAdd (OS_SEM *p_sem) +{ + p_sem->DbgNamePtr = (CPU_CHAR *)((void *)" "); + p_sem->DbgPrevPtr = (OS_SEM *)0; + if (OSSemDbgListPtr == (OS_SEM *)0) { + p_sem->DbgNextPtr = (OS_SEM *)0; + } else { + p_sem->DbgNextPtr = OSSemDbgListPtr; + OSSemDbgListPtr->DbgPrevPtr = p_sem; + } + OSSemDbgListPtr = p_sem; +} + + +void OS_SemDbgListRemove (OS_SEM *p_sem) +{ + OS_SEM *p_sem_next; + OS_SEM *p_sem_prev; + + + p_sem_prev = p_sem->DbgPrevPtr; + p_sem_next = p_sem->DbgNextPtr; + + if (p_sem_prev == (OS_SEM *)0) { + OSSemDbgListPtr = p_sem_next; + if (p_sem_next != (OS_SEM *)0) { + p_sem_next->DbgPrevPtr = (OS_SEM *)0; + } + p_sem->DbgNextPtr = (OS_SEM *)0; + + } else if (p_sem_next == (OS_SEM *)0) { + p_sem_prev->DbgNextPtr = (OS_SEM *)0; + p_sem->DbgPrevPtr = (OS_SEM *)0; + + } else { + p_sem_prev->DbgNextPtr = p_sem_next; + p_sem_next->DbgPrevPtr = p_sem_prev; + p_sem->DbgNextPtr = (OS_SEM *)0; + p_sem->DbgPrevPtr = (OS_SEM *)0; + } +} +#endif +#endif diff --git a/rtos/uC-OS3/Source/os_stat.c b/rtos/uC-OS3/Source/os_stat.c new file mode 100644 index 00000000..b1362fde --- /dev/null +++ b/rtos/uC-OS3/Source/os_stat.c @@ -0,0 +1,571 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* STATISTICS MODULE +* +* File : os_stat.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_stat__c = "$Id: $"; +#endif + + +#if (OS_CFG_STAT_TASK_EN > 0u) + +/* +************************************************************************************************************************ +* RESET STATISTICS +* +* Description: This function is called by your application to reset the statistics. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call succeeded +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSStatReset (OS_ERR *p_err) +{ +#if (OS_CFG_DBG_EN > 0u) + OS_TCB *p_tcb; +#if (OS_MSG_EN > 0u) + OS_MSG_Q *p_msg_q; +#endif +#if (OS_CFG_Q_EN > 0u) + OS_Q *p_q; +#endif +#endif + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_STAT_TASK_EN > 0u) + OSStatTaskCPUUsageMax = 0u; +#if (OS_CFG_TS_EN > 0u) + OSStatTaskTimeMax = 0u; +#endif +#endif + +#if (OS_CFG_TS_EN > 0u) && (OS_CFG_TICK_EN > 0u) + OSTickTime = 0u; + OSTickTimeMax = 0u; +#endif + +#if (OS_CFG_TMR_EN > 0u) +#if (OS_CFG_TS_EN > 0u) + OSTmrTaskTime = 0u; + OSTmrTaskTimeMax = 0u; +#endif +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN +#if (OS_CFG_TS_EN > 0u) + OSIntDisTimeMax = 0u; /* Reset the maximum interrupt disable time */ + CPU_StatReset(); /* Reset CPU-specific performance monitors. */ +#endif +#endif + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + OSSchedLockTimeMax = 0u; /* Reset the maximum scheduler lock time */ +#endif + +#if ((OS_MSG_EN > 0u) && (OS_CFG_DBG_EN > 0u)) + OSMsgPool.NbrUsedMax = 0u; +#endif + CPU_CRITICAL_EXIT(); + +#if (OS_CFG_DBG_EN > 0u) + CPU_CRITICAL_ENTER(); + p_tcb = OSTaskDbgListPtr; + CPU_CRITICAL_EXIT(); + while (p_tcb != (OS_TCB *)0) { /* Reset per-Task statistics */ + CPU_CRITICAL_ENTER(); + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + p_tcb->IntDisTimeMax = 0u; +#endif + +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + p_tcb->SchedLockTimeMax = 0u; +#endif + +#if (OS_CFG_TASK_PROFILE_EN > 0u) +#if (OS_CFG_TASK_Q_EN > 0u) + p_tcb->MsgQPendTimeMax = 0u; +#endif + p_tcb->SemPendTimeMax = 0u; + p_tcb->CtxSwCtr = 0u; + p_tcb->CPUUsage = 0u; + p_tcb->CPUUsageMax = 0u; + p_tcb->CyclesTotal = 0u; + p_tcb->CyclesTotalPrev = 0u; +#if (OS_CFG_TS_EN > 0u) + p_tcb->CyclesStart = OS_TS_GET(); +#endif +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) + p_msg_q = &p_tcb->MsgQ; + p_msg_q->NbrEntriesMax = 0u; +#endif + p_tcb = p_tcb->DbgNextPtr; + CPU_CRITICAL_EXIT(); + } +#endif + +#if (OS_CFG_Q_EN > 0u) && (OS_CFG_DBG_EN > 0u) + CPU_CRITICAL_ENTER(); + p_q = OSQDbgListPtr; + CPU_CRITICAL_EXIT(); + while (p_q != (OS_Q *)0) { /* Reset message queues statistics */ + CPU_CRITICAL_ENTER(); + p_msg_q = &p_q->MsgQ; + p_msg_q->NbrEntriesMax = 0u; + p_q = p_q->DbgNextPtr; + CPU_CRITICAL_EXIT(); + } +#endif + + + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DETERMINE THE CPU CAPACITY +* +* Description: This function is called by your application to establish CPU usage by first determining how high a 32-bit +* counter would count to in 1/10 second if no other tasks were to execute during that time. CPU usage is +* then determined by a low priority task which keeps track of this 32-bit counter every second but this +* time, with other tasks running. CPU usage is determined by: +* +* OS_Stat_IdleCtr +* CPU Usage (%) = 100 * (1 - ------------------) +* OS_Stat_IdleCtrMax +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE The call was successfu +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSStatTaskCPUUsageInit (OS_ERR *p_err) +{ + OS_ERR err; + OS_TICK dly; + CPU_SR_ALLOC(); + + + err = OS_ERR_NONE; /* Initialize err explicitly for static analysis. */ + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if ((OS_CFG_TMR_EN > 0u) && (OS_CFG_TASK_SUSPEND_EN > 0u)) + OSTaskSuspend(&OSTmrTaskTCB, &err); + if (err != OS_ERR_NONE) { + *p_err = err; + return; + } +#endif + + OSTimeDly(2u, /* Synchronize with clock tick */ + (OS_OPT )OS_OPT_TIME_DLY, + (OS_ERR *)&err); + if (err != OS_ERR_NONE) { + *p_err = err; + return; + } + CPU_CRITICAL_ENTER(); + OSStatTaskCtr = 0u; /* Clear idle counter */ + CPU_CRITICAL_EXIT(); + + dly = 0u; + if (OSCfg_TickRate_Hz > OSCfg_StatTaskRate_Hz) { + dly = (OS_TICK)(OSCfg_TickRate_Hz / OSCfg_StatTaskRate_Hz); + } + if (dly == 0u) { + dly = (OSCfg_TickRate_Hz / 10u); + } + + OSTimeDly(dly, /* Determine MAX. idle counter value */ + OS_OPT_TIME_DLY, + &err); + +#if ((OS_CFG_TMR_EN > 0u) && (OS_CFG_TASK_SUSPEND_EN > 0u)) + OSTaskResume(&OSTmrTaskTCB, &err); + if (err != OS_ERR_NONE) { + *p_err = err; + return; + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_TS_EN > 0u) + OSStatTaskTimeMax = 0u; +#endif + + OSStatTaskCtrMax = OSStatTaskCtr; /* Store maximum idle counter count */ + OSStatTaskRdy = OS_STATE_RDY; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* STATISTICS TASK +* +* Description: This task is internal to uC/OS-III and is used to compute some statistics about the multitasking +* environment. Specifically, OS_StatTask() computes the CPU usage. CPU usage is determined by: +* +* OSStatTaskCtr +* OSStatTaskCPUUsage = 100 * (1 - ------------------) (units are in %) +* OSStatTaskCtrMax +* +* Arguments : p_arg this pointer is not used at this time. +* +* Returns : none +* +* Note(s) : 1) This task runs at a priority level higher than the idle task. +* +* 2) You can disable this task by setting the configuration #define OS_CFG_STAT_TASK_EN to 0. +* +* 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the maximum value +* for the idle counter. +* +* 4) This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_StatTask (void *p_arg) +{ +#if (OS_CFG_DBG_EN > 0u) +#if (OS_CFG_TASK_PROFILE_EN > 0u) + OS_CPU_USAGE usage; + OS_CYCLES cycles_total; + OS_CYCLES cycles_div; + OS_CYCLES cycles_mult; + OS_CYCLES cycles_max; +#endif + OS_TCB *p_tcb; +#endif + OS_TICK ctr_max; + OS_TICK ctr_mult; + OS_TICK ctr_div; + OS_ERR err; + OS_TICK dly; +#if (OS_CFG_TS_EN > 0u) + CPU_TS ts_start; +#endif +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) && (OS_CFG_ISR_STK_SIZE > 0u) + CPU_STK *p_stk; + CPU_INT32U free_stk; + CPU_INT32U size_stk; +#endif + CPU_SR_ALLOC(); + + + (void)p_arg; /* Prevent compiler warning for not using 'p_arg' */ + + while (OSStatTaskRdy != OS_TRUE) { + OSTimeDly(2u * OSCfg_StatTaskRate_Hz, /* Wait until statistic task is ready */ + OS_OPT_TIME_DLY, + &err); + } + OSStatReset(&err); /* Reset statistics */ + + dly = (OS_TICK)0; /* Compute statistic task sleep delay */ + if (OSCfg_TickRate_Hz > OSCfg_StatTaskRate_Hz) { + dly = (OSCfg_TickRate_Hz / OSCfg_StatTaskRate_Hz); + } + if (dly == 0u) { + dly = (OSCfg_TickRate_Hz / 10u); + } + + for (;;) { +#if (OS_CFG_TS_EN > 0u) + ts_start = OS_TS_GET(); +#ifdef CPU_CFG_INT_DIS_MEAS_EN + OSIntDisTimeMax = CPU_IntDisMeasMaxGet(); +#endif +#endif + + CPU_CRITICAL_ENTER(); /* ---------------- OVERALL CPU USAGE ----------------- */ + OSStatTaskCtrRun = OSStatTaskCtr; /* Obtain the of the stat counter for the past .1 second*/ + OSStatTaskCtr = 0u; /* Reset the stat counter for the next .1 second */ + CPU_CRITICAL_EXIT(); + + if (OSStatTaskCtrMax > OSStatTaskCtrRun) { /* Compute CPU Usage with best resolution */ + if (OSStatTaskCtrMax < 400000u) { /* 1 to 400,000 */ + ctr_mult = 10000u; + ctr_div = 1u; + } else if (OSStatTaskCtrMax < 4000000u) { /* 400,000 to 4,000,000 */ + ctr_mult = 1000u; + ctr_div = 10u; + } else if (OSStatTaskCtrMax < 40000000u) { /* 4,000,000 to 40,000,000 */ + ctr_mult = 100u; + ctr_div = 100u; + } else if (OSStatTaskCtrMax < 400000000u) { /* 40,000,000 to 400,000,000 */ + ctr_mult = 10u; + ctr_div = 1000u; + } else { /* 400,000,000 and up */ + ctr_mult = 1u; + ctr_div = 10000u; + } + ctr_max = OSStatTaskCtrMax / ctr_div; + OSStatTaskCPUUsage = (OS_CPU_USAGE)((OS_TICK)10000u - ((ctr_mult * OSStatTaskCtrRun) / ctr_max)); + if (OSStatTaskCPUUsageMax < OSStatTaskCPUUsage) { + OSStatTaskCPUUsageMax = OSStatTaskCPUUsage; + } + } else { + OSStatTaskCPUUsage = 0u; + } + + OSStatTaskHook(); /* Invoke user definable hook */ + + +#if (OS_CFG_DBG_EN > 0u) +#if (OS_CFG_TASK_PROFILE_EN > 0u) + cycles_total = 0u; + + CPU_CRITICAL_ENTER(); + p_tcb = OSTaskDbgListPtr; + CPU_CRITICAL_EXIT(); + while (p_tcb != (OS_TCB *)0) { /* ---------------- TOTAL CYCLES COUNT ---------------- */ + CPU_CRITICAL_ENTER(); + p_tcb->CyclesTotalPrev = p_tcb->CyclesTotal; /* Save accumulated # cycles into a temp variable */ + p_tcb->CyclesTotal = 0u; /* Reset total cycles for task for next run */ + CPU_CRITICAL_EXIT(); + + cycles_total += p_tcb->CyclesTotalPrev; /* Perform sum of all task # cycles */ + + CPU_CRITICAL_ENTER(); + p_tcb = p_tcb->DbgNextPtr; + CPU_CRITICAL_EXIT(); + } +#endif + + +#if (OS_CFG_TASK_PROFILE_EN > 0u) + /* ------------ INDIVIDUAL TASK CPU USAGE ------------- */ + if (cycles_total > 0u) { /* 'cycles_total' scaling ... */ + if (cycles_total < 400000u) { /* 1 to 400,000 */ + cycles_mult = 10000u; + cycles_div = 1u; + } else if (cycles_total < 4000000u) { /* 400,000 to 4,000,000 */ + cycles_mult = 1000u; + cycles_div = 10u; + } else if (cycles_total < 40000000u) { /* 4,000,000 to 40,000,000 */ + cycles_mult = 100u; + cycles_div = 100u; + } else if (cycles_total < 400000000u) { /* 40,000,000 to 400,000,000 */ + cycles_mult = 10u; + cycles_div = 1000u; + } else { /* 400,000,000 and up */ + cycles_mult = 1u; + cycles_div = 10000u; + } + cycles_max = cycles_total / cycles_div; + } else { + cycles_mult = 0u; + cycles_max = 1u; + } +#endif + CPU_CRITICAL_ENTER(); + p_tcb = OSTaskDbgListPtr; + CPU_CRITICAL_EXIT(); + while (p_tcb != (OS_TCB *)0) { +#if (OS_CFG_TASK_PROFILE_EN > 0u) /* Compute execution time of each task */ + usage = (OS_CPU_USAGE)(cycles_mult * p_tcb->CyclesTotalPrev / cycles_max); + if (usage > 10000u) { + usage = 10000u; + } + p_tcb->CPUUsage = usage; + if (p_tcb->CPUUsageMax < usage) { /* Detect peak CPU usage */ + p_tcb->CPUUsageMax = usage; + } +#endif + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) + OSTaskStkChk( p_tcb, /* Compute stack usage of active tasks only */ + &p_tcb->StkFree, + &p_tcb->StkUsed, + &err); +#endif + + CPU_CRITICAL_ENTER(); + p_tcb = p_tcb->DbgNextPtr; + CPU_CRITICAL_EXIT(); + } +#endif + + /*------------------ Check ISR Stack -------------------*/ +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) && (OS_CFG_ISR_STK_SIZE > 0u) + free_stk = 0u; +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + p_stk = OSCfg_ISRStkBasePtr; /* Start at the lowest memory and go up */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + p_stk += OS_CFG_TASK_STK_REDZONE_DEPTH; + size_stk = OSCfg_ISRStkSize - OS_CFG_TASK_STK_REDZONE_DEPTH; +#else + size_stk = OSCfg_ISRStkSize; +#endif + while ((*p_stk == 0u) && (free_stk < size_stk)) { /* Compute the number of zero entries on the stk */ + p_stk++; + free_stk++; + } +#else + p_stk = OSCfg_ISRStkBasePtr + OSCfg_ISRStkSize - 1u;/* Start at the highest memory and go down */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + p_stk -= OS_CFG_TASK_STK_REDZONE_DEPTH; + size_stk = OSCfg_ISRStkSize - OS_CFG_TASK_STK_REDZONE_DEPTH; +#else + size_stk = OSCfg_ISRStkSize; +#endif + while ((*p_stk == 0u) && (free_stk < size_stk)) { /* Compute the number of zero entries on the stk */ + free_stk++; + p_stk--; + } +#endif + OSISRStkFree = free_stk; + OSISRStkUsed = OSCfg_ISRStkSize - free_stk; +#endif + + if (OSStatResetFlag == OS_TRUE) { /* Check if need to reset statistics */ + OSStatResetFlag = OS_FALSE; + OSStatReset(&err); + } + +#if (OS_CFG_TS_EN > 0u) + OSStatTaskTime = OS_TS_GET() - ts_start; /*----- Measure execution time of statistic task -------*/ + if (OSStatTaskTimeMax < OSStatTaskTime) { + OSStatTaskTimeMax = OSStatTaskTime; + } +#endif + + OSTimeDly(dly, + OS_OPT_TIME_DLY, + &err); + } +} + + +/* +************************************************************************************************************************ +* INITIALIZE THE STATISTICS +* +* Description: This function is called by OSInit() to initialize the statistic task. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_STAT_STK_INVALID If you specified a NULL stack pointer during configuration +* OS_ERR_STAT_STK_SIZE_INVALID If you didn't specify a large enough stack. +* OS_ERR_STAT_PRIO_INVALID If you specified a priority for the statistic task equal to or +* lower (i.e. higher number) than the idle task. +* OS_ERR_xxx An error code returned by OSTaskCreate() +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_StatTaskInit (OS_ERR *p_err) +{ + OSStatTaskCtr = 0u; + OSStatTaskCtrRun = 0u; + OSStatTaskCtrMax = 0u; + OSStatTaskRdy = OS_STATE_NOT_RDY; /* Statistic task is not ready */ + OSStatResetFlag = OS_FALSE; + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) && (OS_CFG_ISR_STK_SIZE > 0u) + OSISRStkFree = 0u; + OSISRStkUsed = 0u; +#endif + /* --------------- CREATE THE STAT TASK --------------- */ + if (OSCfg_StatTaskStkBasePtr == (CPU_STK *)0) { + *p_err = OS_ERR_STAT_STK_INVALID; + return; + } + + if (OSCfg_StatTaskStkSize < OSCfg_StkSizeMin) { + *p_err = OS_ERR_STAT_STK_SIZE_INVALID; + return; + } + + if (OSCfg_StatTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) { + *p_err = OS_ERR_STAT_PRIO_INVALID; + return; + } + + OSTaskCreate(&OSStatTaskTCB, +#if (OS_CFG_DBG_EN == 0u) + (CPU_CHAR *)0, +#else + (CPU_CHAR *)"uC/OS-III Stat Task", +#endif + OS_StatTask, + (void *)0, + OSCfg_StatTaskPrio, + OSCfg_StatTaskStkBasePtr, + OSCfg_StatTaskStkLimit, + OSCfg_StatTaskStkSize, + 0u, + 0u, + (void *)0, + (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), + p_err); +} + +#endif diff --git a/rtos/uC-OS3/Source/os_task.c b/rtos/uC-OS3/Source/os_task.c new file mode 100644 index 00000000..8faeebda --- /dev/null +++ b/rtos/uC-OS3/Source/os_task.c @@ -0,0 +1,2843 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* TASK MANAGEMENT +* +* File : os_task.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_task__c = "$Id: $"; +#endif + +/* +************************************************************************************************************************ +* CHANGE PRIORITY OF A TASK +* +* Description: This function allows you to change the priority of a task dynamically. Note that the new +* priority MUST be available. +* +* Arguments : p_tcb is the TCB of the tack to change the priority for +* +* prio_new is the new priority +* +* p_err is a pointer to an error code returned by this function: +* +* OS_ERR_NONE Is the call was successful +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PRIO_INVALID If the priority you specify is higher that the maximum allowed +* (i.e. >= (OS_CFG_PRIO_MAX-1)) or already in use by a kernel +* task +* OS_ERR_STATE_INVALID If the task is in an invalid state +* OS_ERR_TASK_CHANGE_PRIO_ISR If you tried to change the task's priority from an ISR +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_CHANGE_PRIO_EN > 0u) +void OSTaskChangePrio (OS_TCB *p_tcb, + OS_PRIO prio_new, + OS_ERR *p_err) +{ +#if (OS_CFG_MUTEX_EN > 0u) + OS_PRIO prio_high; +#endif + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if ((p_tcb != (OS_TCB *)0) && (p_tcb->TaskState == OS_TASK_STATE_DEL)) { + *p_err = OS_ERR_STATE_INVALID; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TASK_CHANGE_PRIO_ISR; + return; + } +#endif + + if (prio_new >= (OS_CFG_PRIO_MAX - 1u)) { /* Cannot set to Idle Task priority */ + *p_err = OS_ERR_PRIO_INVALID; + return; + } + + CPU_CRITICAL_ENTER(); + + if (p_tcb == (OS_TCB *)0) { /* Are we changing the priority of 'self'? */ + if (OSRunning != OS_STATE_OS_RUNNING) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } + p_tcb = OSTCBCurPtr; + } + +#if (OS_CFG_MUTEX_EN > 0u) + p_tcb->BasePrio = prio_new; /* Update base priority */ + + if (p_tcb->MutexGrpHeadPtr != (OS_MUTEX *)0) { /* Owning a mutex? */ + if (prio_new > p_tcb->Prio) { + prio_high = OS_MutexGrpPrioFindHighest(p_tcb); + if (prio_new > prio_high) { + prio_new = prio_high; + } + } + } +#endif + + OS_TaskChangePrio(p_tcb, prio_new); + + OS_TRACE_TASK_PRIO_CHANGE(p_tcb, prio_new); + CPU_CRITICAL_EXIT(); + + if (OSRunning == OS_STATE_OS_RUNNING) { + OSSched(); /* Run highest priority task ready */ + } + + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* CREATE A TASK +* +* Description: This function is used to have uC/OS-III manage the execution of a task. Tasks can either be created +* prior to the start of multitasking or by a running task. A task cannot be created by an ISR. +* +* Arguments : p_tcb is a pointer to the task's TCB +* +* p_name is a pointer to an ASCII string to provide a name to the task. +* +* p_task is a pointer to the task's code +* +* p_arg is a pointer to an optional data area which can be used to pass parameters to +* the task when the task first executes. Where the task is concerned it thinks +* it was invoked and passed the argument 'p_arg' as follows: +* +* void Task (void *p_arg) +* { +* for (;;) { +* Task code; +* } +* } +* +* prio is the task's priority. A unique priority MUST be assigned to each task and the +* lower the number, the higher the priority. +* +* p_stk_base is a pointer to the base address of the stack (i.e. low address). +* +* stk_limit is the number of stack elements to set as 'watermark' limit for the stack. This value +* represents the number of CPU_STK entries left before the stack is full. For example, +* specifying 10% of the 'stk_size' value indicates that the stack limit will be reached +* when the stack reaches 90% full. +* +* stk_size is the size of the stack in number of elements. If CPU_STK is set to CPU_INT08U, +* 'stk_size' corresponds to the number of bytes available. If CPU_STK is set to +* CPU_INT16U, 'stk_size' contains the number of 16-bit entries available. Finally, if +* CPU_STK is set to CPU_INT32U, 'stk_size' contains the number of 32-bit entries +* available on the stack. +* +* q_size is the maximum number of messages that can be sent to the task +* +* time_quanta amount of time (in ticks) for time slice when round-robin between tasks. Specify 0 to use +* the default. +* +* p_ext is a pointer to a user supplied memory location which is used as a TCB extension. +* For example, this user memory can hold the contents of floating-point registers +* during a context switch, the time each task takes to execute, the number of times +* the task has been switched-in, etc. +* +* opt contains additional information (or options) about the behavior of the task. +* See OS_OPT_TASK_xxx in OS.H. Current choices are: +* +* OS_OPT_TASK_NONE No option selected +* OS_OPT_TASK_STK_CHK Stack checking to be allowed for the task +* OS_OPT_TASK_STK_CLR Clear the stack when the task is created +* OS_OPT_TASK_SAVE_FP If the CPU has floating-point registers, save them +* during a context switch. +* OS_OPT_TASK_NO_TLS If the caller doesn't want or need TLS (Thread Local +* Storage) support for the task. If you do not include this +* option, TLS will be supported by default. +* +* p_err is a pointer to an error code that will be set during this call. The value pointer +* to by 'p_err' can be: +* +* OS_ERR_NONE If the function was successful +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the task after you called +* OSSafetyCriticalStart() +* OS_ERR_PRIO_INVALID If the priority you specify is higher that the maximum +* allowed (i.e. >= OS_CFG_PRIO_MAX-1) or, +* OS_ERR_STK_OVF If the stack was overflowed during stack init +* OS_ERR_STK_INVALID If you specified a NULL pointer for 'p_stk_base' +* OS_ERR_STK_SIZE_INVALID If you specified zero for the 'stk_size' +* OS_ERR_STK_LIMIT_INVALID If you specified a 'stk_limit' greater than or equal +* to 'stk_size' +* OS_ERR_TASK_CREATE_ISR If you tried to create a task from an ISR +* OS_ERR_TASK_INVALID If you specified a NULL pointer for 'p_task' +* OS_ERR_TCB_INVALID If you specified a NULL pointer for 'p_tcb' +* +* Returns : none +* +* Note(s) : 1) OSTaskCreate() will return with the error OS_ERR_STK_OVF when a stack overflow is detected +* during stack initialization. In that specific case some memory may have been corrupted. It is +* therefore recommended to treat OS_ERR_STK_OVF as a fatal error. +************************************************************************************************************************ +*/ + +void OSTaskCreate (OS_TCB *p_tcb, + CPU_CHAR *p_name, + OS_TASK_PTR p_task, + void *p_arg, + OS_PRIO prio, + CPU_STK *p_stk_base, + CPU_STK_SIZE stk_limit, + CPU_STK_SIZE stk_size, + OS_MSG_QTY q_size, + OS_TICK time_quanta, + void *p_ext, + OS_OPT opt, + OS_ERR *p_err) +{ + CPU_STK_SIZE i; +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + OS_REG_ID reg_nbr; +#endif +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_ID id; +#endif + + CPU_STK *p_sp; + CPU_STK *p_stk_limit; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* --------- CANNOT CREATE A TASK FROM AN ISR --------- */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_TASK_CREATE_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */ + if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_TCB_INVALID; + return; + } + if (p_task == (OS_TASK_PTR)0u) { /* User must supply a valid task */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_TASK_INVALID; + return; + } + if (p_stk_base == (CPU_STK *)0) { /* User must supply a valid stack base address */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_STK_INVALID; + return; + } + if (stk_size < OSCfg_StkSizeMin) { /* User must supply a valid minimum stack size */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_STK_SIZE_INVALID; + return; + } + if (stk_limit >= stk_size) { /* User must supply a valid stack limit */ + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_STK_LIMIT_INVALID; + return; + } + if ((prio > (OS_CFG_PRIO_MAX - 2u)) && /* Priority must be within 0 and OS_CFG_PRIO_MAX-1 */ + (prio != (OS_CFG_PRIO_MAX - 1u))) { + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_PRIO_INVALID; + return; + } +#endif + + if (prio == (OS_CFG_PRIO_MAX - 1u)) { +#if (OS_CFG_TASK_IDLE_EN > 0u) + if (p_tcb != &OSIdleTaskTCB) { + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use same priority as idle task */ + return; + } +#else + OS_TRACE_TASK_CREATE_FAILED(p_tcb); + *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use same priority as idle task */ + return; +#endif + } + + OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */ + + *p_err = OS_ERR_NONE; + /* -------------- CLEAR THE TASK'S STACK -------------- */ + if (((opt & OS_OPT_TASK_STK_CHK) != 0u) || /* See if stack checking has been enabled */ + ((opt & OS_OPT_TASK_STK_CLR) != 0u)) { /* See if stack needs to be cleared */ + if ((opt & OS_OPT_TASK_STK_CLR) != 0u) { + p_sp = p_stk_base; + for (i = 0u; i < stk_size; i++) { /* Stack grows from HIGH to LOW memory */ + *p_sp = 0u; /* Clear from bottom of stack and up! */ + p_sp++; + } + } + } + /* ------ INITIALIZE THE STACK FRAME OF THE TASK ------ */ +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + p_stk_limit = p_stk_base + stk_limit; +#else + p_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit; +#endif + + p_sp = OSTaskStkInit(p_task, + p_arg, + p_stk_base, + p_stk_limit, + stk_size, + opt); + +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) /* Check if we overflown the stack during init */ + if (p_sp < p_stk_base) { + *p_err = OS_ERR_STK_OVF; + return; + } +#else + if (p_sp > (p_stk_base + stk_size)) { + *p_err = OS_ERR_STK_OVF; + return; + } +#endif + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) /* Initialize Redzoned stack */ + OS_TaskStkRedzoneInit(p_stk_base, stk_size); +#endif + + /* ------------ INITIALIZE THE TCB FIELDS ------------- */ +#if (OS_CFG_DBG_EN > 0u) + p_tcb->TaskEntryAddr = p_task; /* Save task entry point address */ + p_tcb->TaskEntryArg = p_arg; /* Save task entry argument */ +#endif + +#if (OS_CFG_DBG_EN > 0u) + p_tcb->NamePtr = p_name; /* Save task name */ +#else + (void)p_name; +#endif + + p_tcb->Prio = prio; /* Save the task's priority */ + +#if (OS_CFG_MUTEX_EN > 0u) + p_tcb->BasePrio = prio; /* Set the base priority */ +#endif + + p_tcb->StkPtr = p_sp; /* Save the new top-of-stack pointer */ + p_tcb->StkLimitPtr = p_stk_limit; /* Save the stack limit pointer */ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + p_tcb->TimeQuanta = time_quanta; /* Save the #ticks for time slice (0 means not sliced) */ + if (time_quanta == 0u) { + p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; + } else { + p_tcb->TimeQuantaCtr = time_quanta; + } +#else + (void)time_quanta; +#endif + + p_tcb->ExtPtr = p_ext; /* Save pointer to TCB extension */ +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) || (OS_CFG_TASK_STK_REDZONE_EN > 0u)) + p_tcb->StkBasePtr = p_stk_base; /* Save pointer to the base address of the stack */ + p_tcb->StkSize = stk_size; /* Save the stack size (in number of CPU_STK elements) */ +#endif + p_tcb->Opt = opt; /* Save task options */ + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + for (reg_nbr = 0u; reg_nbr < OS_CFG_TASK_REG_TBL_SIZE; reg_nbr++) { + p_tcb->RegTbl[reg_nbr] = 0u; + } +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) + OS_MsgQInit(&p_tcb->MsgQ, /* Initialize the task's message queue */ + q_size); +#else + (void)q_size; +#endif + + OSTaskCreateHook(p_tcb); /* Call user defined hook */ + + OS_TRACE_TASK_CREATE(p_tcb); + OS_TRACE_TASK_SEM_CREATE(p_tcb, p_name); +#if (OS_CFG_TASK_Q_EN > 0u) + OS_TRACE_TASK_MSG_Q_CREATE(&p_tcb->MsgQ, p_name); +#endif + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + for (id = 0u; id < OS_CFG_TLS_TBL_SIZE; id++) { + p_tcb->TLS_Tbl[id] = 0u; + } + OS_TLS_TaskCreate(p_tcb); /* Call TLS hook */ +#endif + /* -------------- ADD TASK TO READY LIST -------------- */ + CPU_CRITICAL_ENTER(); + OS_PrioInsert(p_tcb->Prio); + OS_RdyListInsertTail(p_tcb); + +#if (OS_CFG_DBG_EN > 0u) + OS_TaskDbgListAdd(p_tcb); +#endif + + OSTaskQty++; /* Increment the #tasks counter */ + + if (OSRunning != OS_STATE_OS_RUNNING) { /* Return if multitasking has not started */ + CPU_CRITICAL_EXIT(); + return; + } + + CPU_CRITICAL_EXIT(); + + OSSched(); +} + + +/* +************************************************************************************************************************ +* DELETE A TASK +* +* Description: This function allows you to delete a task. The calling task can delete itself by specifying a NULL +* pointer for 'p_tcb'. The deleted task is returned to the dormant state and can be re-activated by +* creating the deleted task again. +* +* Arguments : p_tcb is the TCB of the tack to delete +* +* p_err is a pointer to an error code returned by this function: +* +* OS_ERR_NONE If the call is successful +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the task after you called +* OSStart() +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_STATE_INVALID If the state of the task is invalid +* OS_ERR_TASK_DEL_IDLE If you attempted to delete uC/OS-III's idle task +* OS_ERR_TASK_DEL_INVALID If you attempted to delete uC/OS-III's ISR handler task +* OS_ERR_TASK_DEL_ISR If you tried to delete a task from an ISR +* +* Returns : none +* +* Note(s) : 1) 'p_err' gets set to OS_ERR_NONE before OSSched() to allow the returned err or code to be monitored even +* for a task that is deleting itself. In this case, 'p_err' MUST point to a global variable that can be +* accessed by another task. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_DEL_EN > 0u) +void OSTaskDel (OS_TCB *p_tcb, + OS_ERR *p_err) +{ +#if (OS_CFG_MUTEX_EN > 0u) + OS_TCB *p_tcb_owner; + OS_PRIO prio_new; +#endif + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to delete from ISR */ + *p_err = OS_ERR_TASK_DEL_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_TASK_IDLE_EN > 0u) + if (p_tcb == &OSIdleTaskTCB) { /* Not allowed to delete the idle task */ + *p_err = OS_ERR_TASK_DEL_IDLE; + return; + } +#endif + + if (p_tcb == (OS_TCB *)0) { /* Delete 'Self'? */ + CPU_CRITICAL_ENTER(); + p_tcb = OSTCBCurPtr; /* Yes. */ + CPU_CRITICAL_EXIT(); + } + + CPU_CRITICAL_ENTER(); + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + OS_RdyListRemove(p_tcb); + break; + + case OS_TASK_STATE_SUSPENDED: + break; + + case OS_TASK_STATE_DLY: /* Task is only delayed, not on any wait list */ + case OS_TASK_STATE_DLY_SUSPENDED: +#if (OS_CFG_TICK_EN > 0u) + OS_TickListRemove(p_tcb); +#endif + break; + + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + switch (p_tcb->PendOn) { /* See what we are pending on */ + case OS_TASK_PEND_ON_NOTHING: + case OS_TASK_PEND_ON_TASK_Q: /* There is no wait list for these two */ + case OS_TASK_PEND_ON_TASK_SEM: + break; + + case OS_TASK_PEND_ON_FLAG: /* Remove from pend list */ + case OS_TASK_PEND_ON_Q: + case OS_TASK_PEND_ON_SEM: + OS_PendListRemove(p_tcb); + break; + +#if (OS_CFG_MUTEX_EN > 0u) + case OS_TASK_PEND_ON_MUTEX: + p_tcb_owner = ((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr; + prio_new = p_tcb_owner->Prio; + OS_PendListRemove(p_tcb); + if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) && + (p_tcb_owner->Prio == p_tcb->Prio)) { /* Has the owner inherited a priority? */ + prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); + prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new; + } + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; + + if (prio_new != p_tcb_owner->Prio) { + OS_TaskChangePrio(p_tcb_owner, prio_new); + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio); + } + break; +#endif + + default: + /* Default case. */ + break; + } +#if (OS_CFG_TICK_EN > 0u) + if ((p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) || + (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED)) { + OS_TickListRemove(p_tcb); + } +#endif + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + return; + } + +#if (OS_CFG_MUTEX_EN > 0u) + if(p_tcb->MutexGrpHeadPtr != (OS_MUTEX *)0) { + OS_MutexGrpPostAll(p_tcb); + } +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) + (void)OS_MsgQFreeAll(&p_tcb->MsgQ); /* Free task's message queue messages */ +#endif + + OSTaskDelHook(p_tcb); /* Call user defined hook */ + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_TaskDel(p_tcb); /* Call TLS hook */ +#endif + +#if (OS_CFG_DBG_EN > 0u) + OS_TaskDbgListRemove(p_tcb); +#endif + + OSTaskQty--; /* One less task being managed */ + + OS_TRACE_TASK_DEL(p_tcb); + +#if (OS_CFG_TASK_STK_REDZONE_EN == 0u) /* Don't clear the TCB before checking the red-zone */ + OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */ +#endif + p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL; /* Indicate that the task was deleted */ + + *p_err = OS_ERR_NONE; /* See Note #1. */ + CPU_CRITICAL_EXIT(); + + OSSched(); /* Find new highest priority task */ +} +#endif + + +/* +************************************************************************************************************************ +* FLUSH TASK's QUEUE +* +* Description: This function is used to flush the task's internal message queue. +* +* Arguments : p_tcb is a pointer to the task's OS_TCB. Specifying a NULL pointer indicates that you wish to +* flush the message queue of the calling task. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE Upon success +* OS_ERR_FLUSH_ISR If you called this function from an ISR +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* +* Returns : The number of entries freed from the queue +* +* Note(s) : 1) You should use this function with great care because, when to flush the queue, you LOOSE the +* references to what the queue entries are pointing to and thus, you could cause 'memory leaks'. In +* other words, the data you are pointing to that's being referenced by the queue entries should, most +* likely, need to be de-allocated (i.e. freed). +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_Q_EN > 0u) +OS_MSG_QTY OSTaskQFlush (OS_TCB *p_tcb, + OS_ERR *p_err) +{ + OS_MSG_QTY entries; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't flush a message queue from an ISR */ + *p_err = OS_ERR_FLUSH_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + + if (p_tcb == (OS_TCB *)0) { /* Flush message queue of calling task? */ + CPU_CRITICAL_ENTER(); + p_tcb = OSTCBCurPtr; + CPU_CRITICAL_EXIT(); + } + + CPU_CRITICAL_ENTER(); + entries = OS_MsgQFreeAll(&p_tcb->MsgQ); /* Return all OS_MSGs to the OS_MSG pool */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (entries); +} +#endif + + +/* +************************************************************************************************************************ +* WAIT FOR A MESSAGE +* +* Description: This function causes the current task to wait for a message to be posted to it. +* +* Arguments : timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for a +* message to arrive up to the amount of time specified by this argument. +* If you specify 0, however, your task will wait forever or, until a message arrives. +* +* opt determines whether the user wants to block if the task's queue is empty or not: +* +* OS_OPT_PEND_BLOCKING +* OS_OPT_PEND_NON_BLOCKING +* +* p_msg_size is a pointer to a variable that will receive the size of the message +* +* p_ts is a pointer to a variable that will receive the timestamp of when the message was +* received. If you pass a NULL pointer (i.e. (CPU_TS *)0) then you will not get the +* timestamp. In other words, passing a NULL pointer is valid and indicates that you don't +* need the timestamp. +* +* p_err is a pointer to where an error message will be deposited. Possible error +* messages are: +* +* OS_ERR_NONE The call was successful and your task received a message. +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT If the pend was aborted +* OS_ERR_PEND_ISR If you called this function from an ISR and the result +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the queue was not empty +* OS_ERR_PTR_INVALID If 'p_msg_size' is NULL +* OS_ERR_SCHED_LOCKED If the scheduler is locked +* OS_ERR_TIMEOUT A message was not received within the specified timeout +* would lead to a suspension +* OS_ERR_TICK_DISABLED If kernel ticks are disabled and a timeout is specified +* +* Returns : A pointer to the message received or a NULL pointer upon error. +* +* Note(s) : 1) It is possible to receive NULL pointers when there are no errors. +* +* : 2) This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_Q_EN > 0u) +void *OSTaskQPend (OS_TICK timeout, + OS_OPT opt, + OS_MSG_SIZE *p_msg_size, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + OS_MSG_Q *p_msg_q; + void *p_void; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((void *)0); + } +#endif + + OS_TRACE_TASK_MSG_Q_PEND_ENTER(&OSTCBCurPtr->MsgQ, timeout, opt, p_msg_size, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + *p_err = OS_ERR_TICK_DISABLED; + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_TICK_DISABLED); + return ((void *)0); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't Pend from an ISR */ + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_PEND_ISR); + *p_err = OS_ERR_PEND_ISR; + return ((void *)0); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return ((void *)0); + } +#endif + + +#if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */ + if (p_msg_size == (OS_MSG_SIZE *)0) { /* User must supply a valid destination for msg size */ + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_PTR_INVALID); + *p_err = OS_ERR_PTR_INVALID; + return ((void *)0); + } + switch (opt) { /* User must supply a valid option */ + case OS_OPT_PEND_BLOCKING: + case OS_OPT_PEND_NON_BLOCKING: + break; + + default: + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return ((void *)0); + } +#endif + + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; /* Initialize the returned timestamp */ + } + + CPU_CRITICAL_ENTER(); + p_msg_q = &OSTCBCurPtr->MsgQ; /* Any message waiting in the message queue? */ + p_void = OS_MsgQGet(p_msg_q, + p_msg_size, + p_ts, + p_err); + if (*p_err == OS_ERR_NONE) { +#if (OS_CFG_TASK_PROFILE_EN > 0u) +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + OSTCBCurPtr->MsgQPendTime = OS_TS_GET() - *p_ts; + if (OSTCBCurPtr->MsgQPendTimeMax < OSTCBCurPtr->MsgQPendTime) { + OSTCBCurPtr->MsgQPendTimeMax = OSTCBCurPtr->MsgQPendTime; + } + } +#endif +#endif + OS_TRACE_TASK_MSG_Q_PEND(p_msg_q); + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_NONE); + return (p_void); /* Yes, Return oldest message received */ + } + + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */ + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */ + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_MSG_Q_PEND_FAILED(p_msg_q); + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + return ((void *)0); + } else { /* Yes */ + if (OSSchedLockNestingCtr > 0u) { /* Can't block when the scheduler is locked */ + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_MSG_Q_PEND_FAILED(p_msg_q); + OS_TRACE_TASK_MSG_Q_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; + return ((void *)0); + } + } + + OS_Pend((OS_PEND_OBJ *)0, /* Block task pending on Message */ + OSTCBCurPtr, + OS_TASK_PEND_ON_TASK_Q, + timeout); + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_MSG_Q_PEND_BLOCK(p_msg_q); + OSSched(); /* Find the next highest priority task ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { + case OS_STATUS_PEND_OK: /* Extract message from TCB (Put there by Post) */ + p_void = OSTCBCurPtr->MsgPtr; + *p_msg_size = OSTCBCurPtr->MsgSize; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; +#if (OS_CFG_TASK_PROFILE_EN > 0u) + OSTCBCurPtr->MsgQPendTime = OS_TS_GET() - OSTCBCurPtr->TS; + if (OSTCBCurPtr->MsgQPendTimeMax < OSTCBCurPtr->MsgQPendTime) { + OSTCBCurPtr->MsgQPendTimeMax = OSTCBCurPtr->MsgQPendTime; + } +#endif + } +#endif + OS_TRACE_TASK_MSG_Q_PEND(p_msg_q); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */ + p_void = (void *)0; + *p_msg_size = 0u; + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } + OS_TRACE_TASK_MSG_Q_PEND_FAILED(p_msg_q); + *p_err = OS_ERR_PEND_ABORT; + break; + + case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get event within TO */ + default: + p_void = (void *)0; + *p_msg_size = 0u; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_TASK_MSG_Q_PEND_FAILED(p_msg_q); + *p_err = OS_ERR_TIMEOUT; + break; + } + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_MSG_Q_PEND_EXIT(*p_err); + return (p_void); /* Return received message */ +} +#endif + + +/* +************************************************************************************************************************ +* ABORT WAITING FOR A MESSAGE +* +* Description: This function aborts & readies the task specified. This function should be used to fault-abort the wait +* for a message, rather than to normally post the message to the task via OSTaskQPost(). +* +* Arguments : p_tcb is a pointer to the task to pend abort +* +* opt provides options for this function: +* +* OS_OPT_POST_NONE No option specified +* OS_OPT_POST_NO_SCHED Indicates that the scheduler will not be called. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE If the task was readied and informed of the aborted wait +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If you called this function from an ISR +* OS_ERR_PEND_ABORT_NONE If task was not pending on a message and thus there is nothing to +* abort +* OS_ERR_PEND_ABORT_SELF If you passed a NULL pointer for 'p_tcb' +* +* Returns : == OS_FALSE if task was not waiting for a message, or upon error. +* == OS_TRUE if task was waiting for a message and was readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_Q_EN > 0u) && (OS_CFG_TASK_Q_PEND_ABORT_EN > 0u) +CPU_BOOLEAN OSTaskQPendAbort (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err) +{ + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + *p_err = OS_ERR_PEND_ABORT_ISR; /* ... can't Pend Abort from an ISR */ + return (OS_FALSE); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */ + switch (opt) { /* User must supply a valid option */ + case OS_OPT_POST_NONE: + case OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (OS_FALSE); + } +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_ARG_CHK_EN > 0u) + if ((p_tcb == (OS_TCB *)0) || /* Pend abort self? */ + (p_tcb == OSTCBCurPtr)) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_PEND_ABORT_SELF; /* ... doesn't make sense */ + return (OS_FALSE); + } +#endif + + if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_Q) { /* Is task waiting for a message? */ + CPU_CRITICAL_EXIT(); /* No */ + *p_err = OS_ERR_PEND_ABORT_NONE; + return (OS_FALSE); + } + +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp of when the abort occurred */ +#else + ts = 0u; +#endif + OS_PendAbort(p_tcb, /* Abort the pend */ + ts, + OS_STATUS_PEND_ABORT); + CPU_CRITICAL_EXIT(); + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + *p_err = OS_ERR_NONE; + return (OS_TRUE); +} +#endif + + +/* +************************************************************************************************************************ +* POST MESSAGE TO A TASK +* +* Description: This function sends a message to a task. +* +* Arguments : p_tcb is a pointer to the TCB of the task receiving a message. If you specify a NULL pointer then +* the message will be posted to the task's queue of the calling task. In other words, you'd be +* posting a message to yourself. +* +* p_void is a pointer to the message to send. +* +* msg_size is the size of the message sent (in bytes) +* +* opt specifies whether the post will be FIFO or LIFO: +* +* OS_OPT_POST_FIFO Post at the end of the queue +* OS_OPT_POST_LIFO Post at the front of the queue +* +* OS_OPT_POST_NO_SCHED Do not run the scheduler after the post +* +* Note(s): 1) OS_OPT_POST_NO_SCHED can be added with one of the other options. +* +* +* p_err is a pointer to a variable that will hold the error code associated +* with the outcome of this call. Errors can be: +* +* OS_ERR_NONE The call was successful and the message was sent +* OS_ERR_MSG_POOL_EMPTY If there are no more OS_MSGs available from the pool +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_Q_MAX If the queue is full +* OS_ERR_STATE_INVALID If the task is in an invalid state. This should never happen +* and if it does, would be considered a system failure +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_Q_EN > 0u) +void OSTaskQPost (OS_TCB *p_tcb, + void *p_void, + OS_MSG_SIZE msg_size, + OS_OPT opt, + OS_ERR *p_err) +{ + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + + OS_TRACE_TASK_MSG_Q_POST_ENTER(&p_tcb->MsgQ, p_void, msg_size, opt); + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_TASK_MSG_Q_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */ + switch (opt) { /* User must supply a valid option */ + case OS_OPT_POST_FIFO: + case OS_OPT_POST_LIFO: + case OS_OPT_POST_FIFO | OS_OPT_POST_NO_SCHED: + case OS_OPT_POST_LIFO | OS_OPT_POST_NO_SCHED: + break; + + default: + OS_TRACE_TASK_MSG_Q_POST_FAILED(&p_tcb->MsgQ); + OS_TRACE_TASK_MSG_Q_POST_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return; + } +#endif + +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + + OS_TRACE_TASK_MSG_Q_POST(&p_tcb->MsgQ); + + *p_err = OS_ERR_NONE; /* Assume we won't have any errors */ + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { /* Post msg to 'self'? */ + p_tcb = OSTCBCurPtr; + } + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + case OS_TASK_STATE_DLY: + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_DLY_SUSPENDED: + OS_MsgQPut(&p_tcb->MsgQ, /* Deposit the message in the queue */ + p_void, + msg_size, + opt, + ts, + p_err); + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_Q) { /* Is task waiting for a message to be sent to it? */ + OS_Post((OS_PEND_OBJ *)0, + p_tcb, + p_void, + msg_size, + ts); + CPU_CRITICAL_EXIT(); + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + } else { + OS_MsgQPut(&p_tcb->MsgQ, /* No, Task is pending on something else ... */ + p_void, /* ... Deposit the message in the task's queue */ + msg_size, + opt, + ts, + p_err); + CPU_CRITICAL_EXIT(); + } + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + break; + } + + OS_TRACE_TASK_MSG_Q_POST_EXIT(*p_err); +} +#endif + + +/* +************************************************************************************************************************ +* GET THE CURRENT VALUE OF A TASK REGISTER +* +* Description: This function is called to obtain the current value of a task register. Task registers are application +* specific and can be used to store task specific values such as 'error numbers' (i.e. errno), statistics, +* etc. +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task you want to read the register from. If 'p_tcb' is a +* NULL pointer then you will get the register of the current task. +* +* id is the 'id' of the desired task variable. Note that the 'id' must be less than +* OS_CFG_TASK_REG_TBL_SIZE +* +* p_err is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE If the call was successful +* OS_ERR_REG_ID_INVALID If the 'id' is not between 0 and OS_CFG_TASK_REG_TBL_SIZE-1 +* +* Returns : The current value of the task's register or 0 if an error is detected. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) +OS_REG OSTaskRegGet (OS_TCB *p_tcb, + OS_REG_ID id, + OS_ERR *p_err) +{ + OS_REG value; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (id >= OS_CFG_TASK_REG_TBL_SIZE) { + *p_err = OS_ERR_REG_ID_INVALID; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { + p_tcb = OSTCBCurPtr; + } + value = p_tcb->RegTbl[id]; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (value); +} +#endif + + +/* +************************************************************************************************************************ +* ALLOCATE THE NEXT AVAILABLE TASK REGISTER ID +* +* Description: This function is called to obtain a task register ID. This function thus allows task registers IDs to be +* allocated dynamically instead of statically. +* +* Arguments : p_err is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE If the call was successful +* OS_ERR_NO_MORE_ID_AVAIL If you are attempting to assign more task register IDs than you +* have available through OS_CFG_TASK_REG_TBL_SIZE +* +* Returns : The next available task register 'id' or OS_CFG_TASK_REG_TBL_SIZE if an error is detected. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) +OS_REG_ID OSTaskRegGetID (OS_ERR *p_err) +{ + OS_REG_ID id; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return ((OS_REG_ID)OS_CFG_TASK_REG_TBL_SIZE); + } +#endif + + CPU_CRITICAL_ENTER(); + if (OSTaskRegNextAvailID >= OS_CFG_TASK_REG_TBL_SIZE) { /* See if we exceeded the number of IDs available */ + *p_err = OS_ERR_NO_MORE_ID_AVAIL; /* Yes, cannot allocate more task register IDs */ + CPU_CRITICAL_EXIT(); + return (OS_CFG_TASK_REG_TBL_SIZE); + } + + id = OSTaskRegNextAvailID; /* Assign the next available ID */ + OSTaskRegNextAvailID++; /* Increment available ID for next request */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (id); +} +#endif + + +/* +************************************************************************************************************************ +* SET THE CURRENT VALUE OF A TASK REGISTER +* +* Description: This function is called to change the current value of a task register. Task registers are application +* specific and can be used to store task specific values such as 'error numbers' (i.e. errno), statistics, +* etc. +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task you want to set the register for. If 'p_tcb' is a NULL +* pointer then you will change the register of the current task. +* +* id is the 'id' of the desired task register. Note that the 'id' must be less than +* OS_CFG_TASK_REG_TBL_SIZE +* +* value is the desired value for the task register. +* +* p_err is a pointer to a variable that will hold an error code related to this call. +* +* OS_ERR_NONE If the call was successful +* OS_ERR_REG_ID_INVALID If the 'id' is not between 0 and OS_CFG_TASK_REG_TBL_SIZE-1 +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) +void OSTaskRegSet (OS_TCB *p_tcb, + OS_REG_ID id, + OS_REG value, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (id >= OS_CFG_TASK_REG_TBL_SIZE) { + *p_err = OS_ERR_REG_ID_INVALID; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { + p_tcb = OSTCBCurPtr; + } + p_tcb->RegTbl[id] = value; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* RESUME A SUSPENDED TASK +* +* Description: This function is called to resume a previously suspended task. This is the only call that will remove an +* explicit task suspension. +* +* Arguments : p_tcb Is a pointer to the task's OS_TCB to resume +* +* p_err Is a pointer to a variable that will contain an error code returned by this function +* +* OS_ERR_NONE If the requested task is resumed +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_STATE_INVALID If the task is in an invalid state +* OS_ERR_TASK_NOT_SUSPENDED If the task to resume has not been suspended +* OS_ERR_TASK_RESUME_ISR If you called this function from an ISR +* OS_ERR_TASK_RESUME_SELF You cannot resume 'self' +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_SUSPEND_EN > 0u) +void OSTaskResume (OS_TCB *p_tcb, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + OS_TRACE_TASK_RESUME_ENTER(p_tcb); + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TASK_RESUME_ISR; + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_TASK_RESUME_ISR); + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_OS_NOT_RUNNING); + return; + } +#endif + + +#if (OS_CFG_ARG_CHK_EN > 0u) + CPU_CRITICAL_ENTER(); + if ((p_tcb == (OS_TCB *)0) || /* We cannot resume 'self' */ + (p_tcb == OSTCBCurPtr)) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_RESUME_SELF; + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_TASK_RESUME_SELF); + return; + } + CPU_CRITICAL_EXIT(); +#endif + + CPU_CRITICAL_ENTER(); + *p_err = OS_ERR_NONE; + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + case OS_TASK_STATE_DLY: + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_NOT_SUSPENDED; + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_TASK_NOT_SUSPENDED); + break; + + case OS_TASK_STATE_SUSPENDED: + p_tcb->SuspendCtr--; + if (p_tcb->SuspendCtr == 0u) { + p_tcb->TaskState = OS_TASK_STATE_RDY; + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + OS_TRACE_TASK_RESUME(p_tcb); + } + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_DLY_SUSPENDED: + p_tcb->SuspendCtr--; + if (p_tcb->SuspendCtr == 0u) { + p_tcb->TaskState = OS_TASK_STATE_DLY; + } + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND_SUSPENDED: + p_tcb->SuspendCtr--; + if (p_tcb->SuspendCtr == 0u) { + p_tcb->TaskState = OS_TASK_STATE_PEND; + } + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + p_tcb->SuspendCtr--; + if (p_tcb->SuspendCtr == 0u) { + p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT; + } + CPU_CRITICAL_EXIT(); + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_STATE_INVALID); + break; + } + + if (*p_err != OS_ERR_NONE) { /* Don't schedule if task wasn't in a suspend state. */ + return; + } + + OSSched(); + OS_TRACE_TASK_RESUME_EXIT(OS_ERR_NONE); +} +#endif + + +/* +************************************************************************************************************************ +* WAIT FOR A TASK SEMAPHORE +* +* Description: This function is called to block the current task until a signal is sent by another task or ISR. +* +* Arguments : timeout is the amount of time you are will to wait for the signal +* +* opt determines whether the user wants to block if a semaphore post was not received: +* +* OS_OPT_PEND_BLOCKING +* OS_OPT_PEND_NON_BLOCKING +* +* p_ts is a pointer to a variable that will receive the timestamp of when the semaphore was posted +* or pend aborted. If you pass a NULL pointer (i.e. (CPU_TS *)0) then you will not get the +* timestamp. In other words, passing a NULL pointer is valid and indicates that you don't +* need the timestamp. +* +* p_err is a pointer to an error code that will be set by this function +* +* OS_ERR_NONE The call was successful and your task received a message +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT If the pend was aborted +* OS_ERR_PEND_ISR If you called this function from an ISR +* OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but no signal was received +* OS_ERR_SCHED_LOCKED If the scheduler is locked +* OS_ERR_STATUS_INVALID If the pend status is invalid +* OS_ERR_TIMEOUT A message was not received within the specified timeout +* +* Returns : The current count of signals the task received, 0 if none. +* +* Note(s) : This API 'MUST NOT' be called from a timer callback function. +************************************************************************************************************************ +*/ + +OS_SEM_CTR OSTaskSemPend (OS_TICK timeout, + OS_OPT opt, + CPU_TS *p_ts, + OS_ERR *p_err) +{ + OS_SEM_CTR ctr; + CPU_SR_ALLOC(); + + +#if (OS_CFG_TS_EN == 0u) + (void)p_ts; /* Prevent compiler warning for not using 'ts' */ +#endif + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_TASK_SEM_PEND_ENTER(OSTCBCurPtr, timeout, opt, p_ts); + +#if (OS_CFG_TICK_EN == 0u) + if (timeout != 0u) { + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_TICK_DISABLED); + *p_err = OS_ERR_TICK_DISABLED; + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_PEND_ISR); + *p_err = OS_ERR_PEND_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + switch (opt) { /* Validate 'opt' */ + case OS_OPT_PEND_BLOCKING: + case OS_OPT_PEND_NON_BLOCKING: + break; + + default: + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + if (OSTCBCurPtr->SemCtr > 0u) { /* See if task already been signaled */ + OSTCBCurPtr->SemCtr--; + ctr = OSTCBCurPtr->SemCtr; +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#if (OS_CFG_TASK_PROFILE_EN > 0u) +#if (OS_CFG_TS_EN > 0u) + OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS; + if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->SemPendTime) { + OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime; + } +#endif +#endif +#endif + OS_TRACE_TASK_SEM_PEND(OSTCBCurPtr); + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_NONE); + *p_err = OS_ERR_NONE; + return (ctr); + } + + if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u) { /* Caller wants to block if not available? */ + CPU_CRITICAL_EXIT(); +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); + *p_err = OS_ERR_PEND_WOULD_BLOCK; /* No */ + return (0u); + } else { /* Yes */ + if (OSSchedLockNestingCtr > 0u) { /* Can't pend when the scheduler is locked */ +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + OS_TRACE_TASK_SEM_PEND_EXIT(OS_ERR_SCHED_LOCKED); + *p_err = OS_ERR_SCHED_LOCKED; + return (0u); + } + } + + OS_Pend((OS_PEND_OBJ *)0, /* Block task pending on Signal */ + OSTCBCurPtr, + OS_TASK_PEND_ON_TASK_SEM, + timeout); + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_SEM_PEND_BLOCK(OSTCBCurPtr); + OSSched(); /* Find next highest priority task ready to run */ + + CPU_CRITICAL_ENTER(); + switch (OSTCBCurPtr->PendStatus) { /* See if we timed-out or aborted */ + case OS_STATUS_PEND_OK: +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; +#if (OS_CFG_TASK_PROFILE_EN > 0u) +#if (OS_CFG_TS_EN > 0u) + OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS; + if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->SemPendTime) { + OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime; + } +#endif +#endif + } +#endif + OS_TRACE_TASK_SEM_PEND(OSTCBCurPtr); + *p_err = OS_ERR_NONE; + break; + + case OS_STATUS_PEND_ABORT: +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = OSTCBCurPtr->TS; + } +#endif + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + *p_err = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ + break; + + case OS_STATUS_PEND_TIMEOUT: +#if (OS_CFG_TS_EN > 0u) + if (p_ts != (CPU_TS *)0) { + *p_ts = 0u; + } +#endif + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + *p_err = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ + break; + + default: + OS_TRACE_TASK_SEM_PEND_FAILED(OSTCBCurPtr); + *p_err = OS_ERR_STATUS_INVALID; + break; + } + ctr = OSTCBCurPtr->SemCtr; + CPU_CRITICAL_EXIT(); + OS_TRACE_TASK_SEM_PEND_EXIT(*p_err); + return (ctr); +} + + +/* +************************************************************************************************************************ +* ABORT WAITING FOR A SIGNAL +* +* Description: This function aborts & readies the task specified. This function should be used to fault-abort the wait +* for a signal, rather than to normally post the signal to the task via OSTaskSemPost(). +* +* Arguments : p_tcb is a pointer to the task to pend abort +* +* opt provides options for this function: +* +* OS_OPT_POST_NONE No option selected +* OS_OPT_POST_NO_SCHED Indicates that the scheduler will not be called. +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE If the task was readied and informed of the aborted wait +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_PEND_ABORT_ISR If you tried calling this function from an ISR +* OS_ERR_PEND_ABORT_NONE If the task was not waiting for a signal +* OS_ERR_PEND_ABORT_SELF If you attempted to pend abort the calling task. This is not +* possible since the calling task cannot be pending because it's +* running +* +* Returns : == OS_FALSE if task was not waiting for a message, or upon error. +* == OS_TRUE if task was waiting for a message and was readied and informed. +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_SEM_PEND_ABORT_EN > 0u) +CPU_BOOLEAN OSTaskSemPendAbort (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err) +{ + CPU_TS ts; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if called from ISR ... */ + *p_err = OS_ERR_PEND_ABORT_ISR; /* ... can't Pend Abort from an ISR */ + return (OS_FALSE); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + switch (opt) { /* Validate 'opt' */ + case OS_OPT_POST_NONE: + case OS_OPT_POST_NO_SCHED: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return (OS_FALSE); + } +#endif + + CPU_CRITICAL_ENTER(); + if ((p_tcb == (OS_TCB *)0) || /* Pend abort self? */ + (p_tcb == OSTCBCurPtr)) { + CPU_CRITICAL_EXIT(); /* ... doesn't make sense! */ + *p_err = OS_ERR_PEND_ABORT_SELF; + return (OS_FALSE); + } + + if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_SEM) { /* Is task waiting for a signal? */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_PEND_ABORT_NONE; + return (OS_FALSE); + } + CPU_CRITICAL_EXIT(); + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); +#else + ts = 0u; +#endif + OS_PendAbort(p_tcb, /* Abort the pend */ + ts, + OS_STATUS_PEND_ABORT); + CPU_CRITICAL_EXIT(); + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + *p_err = OS_ERR_NONE; + return (OS_TRUE); +} +#endif + + +/* +************************************************************************************************************************ +* SIGNAL A TASK +* +* Description: This function is called to signal a task waiting for a signal. +* +* Arguments : p_tcb is the pointer to the TCB of the task to signal. A NULL pointer indicates that you are sending +* a signal to yourself. +* +* opt determines the type of POST performed: +* +* OS_OPT_POST_NONE No option +* OS_OPT_POST_NO_SCHED Do not call the scheduler +* +* p_err is a pointer to an error code returned by this function: +* +* OS_ERR_NONE If the requested task is signaled +* OS_ERR_OPT_INVALID If you specified an invalid option +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow +* OS_ERR_STATE_INVALID If the task is in an invalid state. This should never happen +* and if it does, would be considered a system failure +* +* Returns : The current value of the task's signal counter or 0 if called from an ISR +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_SEM_CTR ctr; + CPU_TS ts; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + OS_TRACE_TASK_SEM_POST_ENTER(p_tcb, opt); + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + OS_TRACE_TASK_SEM_POST_EXIT(OS_ERR_OS_NOT_RUNNING); + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + switch (opt) { /* Validate 'opt' */ + case OS_OPT_POST_NONE: + case OS_OPT_POST_NO_SCHED: + break; + + default: + OS_TRACE_TASK_SEM_POST_FAILED(p_tcb); + OS_TRACE_TASK_SEM_POST_EXIT(OS_ERR_OPT_INVALID); + *p_err = OS_ERR_OPT_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ +#else + ts = 0u; +#endif + + OS_TRACE_TASK_SEM_POST(p_tcb); + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { /* Post signal to 'self'? */ + p_tcb = OSTCBCurPtr; + } +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = ts; +#endif + *p_err = OS_ERR_NONE; /* Assume we won't have any errors */ + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + case OS_TASK_STATE_DLY: + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_DLY_SUSPENDED: + if (p_tcb->SemCtr == (OS_SEM_CTR)-1) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_SEM_OVF; + OS_TRACE_SEM_POST_EXIT(*p_err); + return (0u); + } + p_tcb->SemCtr++; /* Task signaled is not pending on anything */ + ctr = p_tcb->SemCtr; + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_SEM) { /* Is task signaled waiting for a signal? */ + OS_Post((OS_PEND_OBJ *)0, /* Task is pending on signal */ + p_tcb, + (void *)0, + 0u, + ts); + ctr = p_tcb->SemCtr; + CPU_CRITICAL_EXIT(); + if ((opt & OS_OPT_POST_NO_SCHED) == 0u) { + OSSched(); /* Run the scheduler */ + } + } else { + if (p_tcb->SemCtr == (OS_SEM_CTR)-1) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_SEM_OVF; + OS_TRACE_SEM_POST_EXIT(*p_err); + return (0u); + } + p_tcb->SemCtr++; /* No, Task signaled is NOT pending on semaphore ... */ + ctr = p_tcb->SemCtr; /* ... it must be waiting on something else */ + CPU_CRITICAL_EXIT(); + } + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + ctr = 0u; + break; + } + + OS_TRACE_TASK_SEM_POST_EXIT(*p_err); + + return (ctr); +} + + +/* +************************************************************************************************************************ +* SET THE SIGNAL COUNTER OF A TASK +* +* Description: This function is called to clear the signal counter +* +* Arguments : p_tcb is the pointer to the TCB of the task to clear the counter. If you specify a NULL pointer +* then the signal counter of the current task will be cleared. +* +* cnt is the desired value of the semaphore counter +* +* p_err is a pointer to an error code returned by this function +* +* OS_ERR_NONE If the signal counter of the requested task is set +* OS_ERR_SET_ISR If the function was called from an ISR +* OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_SEM_CTR OSTaskSemSet (OS_TCB *p_tcb, + OS_SEM_CTR cnt, + OS_ERR *p_err) +{ + OS_SEM_CTR ctr; + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_SET_ISR; + return (0u); + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { + p_tcb = OSTCBCurPtr; + } + + if (((p_tcb->TaskState & OS_TASK_STATE_PEND) != 0u) && /* Not allowed when a task is waiting. */ + (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_SEM)) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_WAITING; + return (0u); + } + + ctr = p_tcb->SemCtr; + p_tcb->SemCtr = (OS_SEM_CTR)cnt; + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + return (ctr); +} + + +/* +************************************************************************************************************************ +* STACK CHECKING +* +* Description: This function is called to calculate the amount of free memory left on the specified task's stack. +* +* Arguments : p_tcb is a pointer to the TCB of the task to check. If you specify a NULL pointer then +* you are specifying that you want to check the stack of the current task. +* +* p_free is a pointer to a variable that will receive the number of free 'entries' on the task's stack. +* +* p_used is a pointer to a variable that will receive the number of used 'entries' on the task's stack. +* +* p_err is a pointer to a variable that will contain an error code. +* +* OS_ERR_NONE Upon success +* OS_ERR_PTR_INVALID If either 'p_free' or 'p_used' are NULL pointers +* OS_ERR_TASK_NOT_EXIST If the stack pointer of the task is a NULL pointer +* OS_ERR_TASK_OPT If you did NOT specified OS_OPT_TASK_STK_CHK when the task +* was created +* OS_ERR_TASK_STK_CHK_ISR You called this function from an ISR +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) +void OSTaskStkChk (OS_TCB *p_tcb, + CPU_STK_SIZE *p_free, + CPU_STK_SIZE *p_used, + OS_ERR *p_err) +{ + CPU_STK_SIZE free_stk; + CPU_STK_SIZE stk_size; + CPU_STK *p_stk; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to check stack from ISR */ + *p_err = OS_ERR_TASK_STK_CHK_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_free == (CPU_STK_SIZE *)0) { /* User must specify valid destinations for the sizes */ + *p_err = OS_ERR_PTR_INVALID; + return; + } + + if (p_used == (CPU_STK_SIZE *)0) { + *p_err = OS_ERR_PTR_INVALID; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { /* Check the stack of the current task? */ + p_tcb = OSTCBCurPtr; /* Yes */ + } + + if (p_tcb->StkPtr == (CPU_STK *)0) { /* Make sure task exist */ + CPU_CRITICAL_EXIT(); + *p_free = 0u; + *p_used = 0u; + *p_err = OS_ERR_TASK_NOT_EXIST; + return; + } + + if ((p_tcb->Opt & OS_OPT_TASK_STK_CHK) == 0u) { /* Make sure stack checking option is set */ + CPU_CRITICAL_EXIT(); + *p_free = 0u; + *p_used = 0u; + *p_err = OS_ERR_TASK_OPT; + return; + } + +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + p_stk = p_tcb->StkBasePtr; /* Start at the lowest memory and go up */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + p_stk += OS_CFG_TASK_STK_REDZONE_DEPTH; +#endif +#else + p_stk = p_tcb->StkBasePtr + p_tcb->StkSize - 1u; /* Start at the highest memory and go down */ +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) + p_stk -= OS_CFG_TASK_STK_REDZONE_DEPTH; +#endif +#endif + + stk_size = p_tcb->StkSize; + CPU_CRITICAL_EXIT(); + + free_stk = 0u; + /* Compute the number of zero entries on the stk */ +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + while ((free_stk < stk_size) && + (*p_stk == 0u)) { + p_stk++; + free_stk++; + } +#else + while ((free_stk < stk_size) && + (*p_stk == 0u)) { + free_stk++; + p_stk--; + } +#endif + *p_free = free_stk; + *p_used = (stk_size - free_stk); /* Compute number of entries used on the stack */ + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* CHECK THE STACK REDZONE OF A TASK +* +* Description: Verify a task's stack redzone. +* +* Arguments : p_tcb is a pointer to the TCB of the task to check or null for the current task. +* +* Returns : If the stack is corrupted (OS_FALSE) or not (OS_TRUE). +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +CPU_BOOLEAN OSTaskStkRedzoneChk (OS_TCB *p_tcb) +{ + CPU_BOOLEAN stk_status; + + + if (p_tcb == (OS_TCB *)0) { + p_tcb = OSTCBCurPtr; + } + /* Check if SP is valid: */ + /* StkBase <= SP < (StkBase + StkSize) */ + if ((p_tcb->StkPtr < p_tcb->StkBasePtr) || + (p_tcb->StkPtr >= (p_tcb->StkBasePtr + p_tcb->StkSize))) { + return (OS_FALSE); + } + + stk_status = OS_TaskStkRedzoneChk(p_tcb->StkBasePtr, p_tcb->StkSize); + + return (stk_status); +} +#endif + + +/* +************************************************************************************************************************ +* SUSPEND A TASK +* +* Description: This function is called to suspend a task. The task can be the calling task if 'p_tcb' is a NULL pointer +* or the pointer to the TCB of the calling task. +* +* Arguments : p_tcb is a pointer to the TCB to suspend. +* If p_tcb is a NULL pointer then, suspend the current task. +* +* p_err is a pointer to a variable that will receive an error code from this function. +* +* OS_ERR_NONE If the requested task is suspended +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SCHED_LOCKED You can't suspend the current task is the scheduler is +* locked +* OS_ERR_STATE_INVALID If the task is in an invalid state +* OS_ERR_TASK_SUSPEND_CTR_OVF If the nesting counter overflowed. +* OS_ERR_TASK_SUSPEND_ISR If you called this function from an ISR +* OS_ERR_TASK_SUSPEND_IDLE If you attempted to suspend the idle task which is not +* allowed +* OS_ERR_TASK_SUSPEND_INT_HANDLER If you attempted to suspend the idle task which is not +* allowed +* +* Returns : none +* +* Note(s) : 1) You should use this function with great care. If you suspend a task that is waiting for an event +* (i.e. a message, a semaphore, a queue ...) you will prevent this task from running when the event +* arrives. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_SUSPEND_EN > 0u) +void OSTaskSuspend (OS_TCB *p_tcb, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + OS_TRACE_TASK_SUSPEND_ENTER(p_tcb); + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TASK_SUSPEND_ISR; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_TASK_SUSPEND_ISR); + return; + } +#endif + +#if (OS_CFG_TASK_IDLE_EN > 0u) + if (p_tcb == &OSIdleTaskTCB) { /* Make sure not suspending the idle task */ + *p_err = OS_ERR_TASK_SUSPEND_IDLE; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_TASK_SUSPEND_IDLE); + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { /* See if specified to suspend self */ + if (OSRunning != OS_STATE_OS_RUNNING) { /* Can't suspend self when the kernel isn't running */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_OS_NOT_RUNNING; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_OS_NOT_RUNNING); + return; + } + p_tcb = OSTCBCurPtr; + } + + if (p_tcb == OSTCBCurPtr) { + if (OSSchedLockNestingCtr > 0u) { /* Can't suspend when the scheduler is locked */ + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_SCHED_LOCKED; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_SCHED_LOCKED); + return; + } + } + + *p_err = OS_ERR_NONE; + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; + p_tcb->SuspendCtr = 1u; + OS_RdyListRemove(p_tcb); + OS_TRACE_TASK_SUSPEND(p_tcb); + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_DLY: + p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED; + p_tcb->SuspendCtr = 1u; + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND: + p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED; + p_tcb->SuspendCtr = 1u; + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_PEND_TIMEOUT: + p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED; + p_tcb->SuspendCtr = 1u; + CPU_CRITICAL_EXIT(); + break; + + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_DLY_SUSPENDED: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + if (p_tcb->SuspendCtr == (OS_NESTING_CTR)-1) { + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_SUSPEND_CTR_OVF; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_TASK_SUSPEND_CTR_OVF); + return; + } + p_tcb->SuspendCtr++; + CPU_CRITICAL_EXIT(); + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_STATE_INVALID); + return; + } + + if (OSRunning == OS_STATE_OS_RUNNING) { /* Only schedule when the kernel is running */ + OSSched(); + OS_TRACE_TASK_SUSPEND_EXIT(OS_ERR_NONE); + } +} +#endif + + +/* +************************************************************************************************************************ +* CHANGE A TASK'S TIME SLICE +* +* Description: This function is called to change the value of the task's specific time slice. +* +* Arguments : p_tcb is the pointer to the TCB of the task to change. If you specify an NULL pointer, the current +* task is assumed. +* +* time_quanta is the number of ticks before the CPU is taken away when round-robin scheduling is enabled. +* +* p_err is a pointer to an error code returned by this function: +* +* OS_ERR_NONE Upon success +* OS_ERR_SET_ISR If you called this function from an ISR +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) +void OSTaskTimeQuantaSet (OS_TCB *p_tcb, + OS_TICK time_quanta, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Can't call this function from an ISR */ + *p_err = OS_ERR_SET_ISR; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + if (p_tcb == (OS_TCB *)0) { + p_tcb = OSTCBCurPtr; + } + + if (time_quanta == 0u) { + p_tcb->TimeQuanta = OSSchedRoundRobinDfltTimeQuanta; + } else { + p_tcb->TimeQuanta = time_quanta; + } + if (p_tcb->TimeQuanta > p_tcb->TimeQuantaCtr) { + p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; + } + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +} +#endif + + +/* +************************************************************************************************************************ +* ADD/REMOVE TASK TO/FROM DEBUG LIST +* +* Description: These functions are called by uC/OS-III to add or remove an OS_TCB from the debug list. +* +* Arguments : p_tcb is a pointer to the OS_TCB to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_DBG_EN > 0u) +void OS_TaskDbgListAdd (OS_TCB *p_tcb) +{ + p_tcb->DbgPrevPtr = (OS_TCB *)0; + if (OSTaskDbgListPtr == (OS_TCB *)0) { + p_tcb->DbgNextPtr = (OS_TCB *)0; + } else { + p_tcb->DbgNextPtr = OSTaskDbgListPtr; + OSTaskDbgListPtr->DbgPrevPtr = p_tcb; + } + OSTaskDbgListPtr = p_tcb; +} + + + +void OS_TaskDbgListRemove (OS_TCB *p_tcb) +{ + OS_TCB *p_tcb_next; + OS_TCB *p_tcb_prev; + + + p_tcb_prev = p_tcb->DbgPrevPtr; + p_tcb_next = p_tcb->DbgNextPtr; + + if (p_tcb_prev == (OS_TCB *)0) { + OSTaskDbgListPtr = p_tcb_next; + if (p_tcb_next != (OS_TCB *)0) { + p_tcb_next->DbgPrevPtr = (OS_TCB *)0; + } + p_tcb->DbgNextPtr = (OS_TCB *)0; + + } else if (p_tcb_next == (OS_TCB *)0) { + p_tcb_prev->DbgNextPtr = (OS_TCB *)0; + p_tcb->DbgPrevPtr = (OS_TCB *)0; + + } else { + p_tcb_prev->DbgNextPtr = p_tcb_next; + p_tcb_next->DbgPrevPtr = p_tcb_prev; + p_tcb->DbgNextPtr = (OS_TCB *)0; + p_tcb->DbgPrevPtr = (OS_TCB *)0; + } +} +#endif + + +/* +************************************************************************************************************************ +* TASK MANAGER INITIALIZATION +* +* Description: This function is called by OSInit() to initialize the task management. +* + +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE the call was successful +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_TaskInit (OS_ERR *p_err) +{ +#if (OS_CFG_DBG_EN > 0u) + OSTaskDbgListPtr = (OS_TCB *)0; +#endif + + OSTaskQty = 0u; /* Clear the number of tasks */ + +#if ((OS_CFG_TASK_PROFILE_EN > 0u) || (OS_CFG_DBG_EN > 0u)) + OSTaskCtxSwCtr = 0u; /* Clear the context switch counter */ +#endif + + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* INITIALIZE TCB FIELDS +* +* Description: This function is called to initialize a TCB to default values +* +* Arguments : p_tcb is a pointer to the TCB to initialize +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_TaskInitTCB (OS_TCB *p_tcb) +{ +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + OS_REG_ID reg_id; +#endif +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + OS_TLS_ID id; +#endif + + + p_tcb->StkPtr = (CPU_STK *)0; + p_tcb->StkLimitPtr = (CPU_STK *)0; + + p_tcb->ExtPtr = (void *)0; + + p_tcb->NextPtr = (OS_TCB *)0; + p_tcb->PrevPtr = (OS_TCB *)0; + +#if (OS_CFG_TICK_EN > 0u) + p_tcb->TickNextPtr = (OS_TCB *)0; + p_tcb->TickPrevPtr = (OS_TCB *)0; +#endif + +#if (OS_CFG_DBG_EN > 0u) + p_tcb->NamePtr = (CPU_CHAR *)((void *)"?Task"); +#endif + +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_STK_CHK_EN > 0u)) + p_tcb->StkBasePtr = (CPU_STK *)0; +#endif + +#if (OS_CFG_DBG_EN > 0u) + p_tcb->TaskEntryAddr = (OS_TASK_PTR )0; + p_tcb->TaskEntryArg = (void *)0; +#endif + +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = 0u; +#endif + +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = (void *)0; + p_tcb->MsgSize = 0u; +#endif + +#if (OS_CFG_TASK_Q_EN > 0u) + OS_MsgQInit(&p_tcb->MsgQ, + 0u); +#if (OS_CFG_TASK_PROFILE_EN > 0u) + p_tcb->MsgQPendTime = 0u; + p_tcb->MsgQPendTimeMax = 0u; +#endif +#endif + +#if (OS_CFG_FLAG_EN > 0u) + p_tcb->FlagsPend = 0u; + p_tcb->FlagsOpt = 0u; + p_tcb->FlagsRdy = 0u; +#endif + +#if (OS_CFG_TASK_REG_TBL_SIZE > 0u) + for (reg_id = 0u; reg_id < OS_CFG_TASK_REG_TBL_SIZE; reg_id++) { + p_tcb->RegTbl[reg_id] = 0u; + } +#endif + +#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) + for (id = 0u; id < OS_CFG_TLS_TBL_SIZE; id++) { + p_tcb->TLS_Tbl[id] = 0u; + } +#endif + + p_tcb->SemCtr = 0u; +#if (OS_CFG_TASK_PROFILE_EN > 0u) + p_tcb->SemPendTime = 0u; + p_tcb->SemPendTimeMax = 0u; +#endif + +#if ((OS_CFG_DBG_EN > 0u) || (OS_CFG_STAT_TASK_STK_CHK_EN > 0u)) + p_tcb->StkSize = 0u; +#endif + + +#if (OS_CFG_TASK_SUSPEND_EN > 0u) + p_tcb->SuspendCtr = 0u; +#endif + +#if (OS_CFG_STAT_TASK_STK_CHK_EN > 0u) + p_tcb->StkFree = 0u; + p_tcb->StkUsed = 0u; +#endif + + p_tcb->Opt = 0u; + +#if (OS_CFG_TICK_EN > 0u) + p_tcb->TickRemain = 0u; + p_tcb->TickCtrPrev = 0u; +#endif + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + p_tcb->TimeQuanta = 0u; + p_tcb->TimeQuantaCtr = 0u; +#endif + +#if (OS_CFG_TASK_PROFILE_EN > 0u) + p_tcb->CPUUsage = 0u; + p_tcb->CPUUsageMax = 0u; + p_tcb->CtxSwCtr = 0u; + p_tcb->CyclesDelta = 0u; +#if (OS_CFG_TS_EN > 0u) + p_tcb->CyclesStart = OS_TS_GET(); /* Read the current timestamp and save */ +#else + p_tcb->CyclesStart = 0u; +#endif + p_tcb->CyclesTotal = 0u; +#endif + +#ifdef CPU_CFG_INT_DIS_MEAS_EN + p_tcb->IntDisTimeMax = 0u; +#endif +#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u) + p_tcb->SchedLockTimeMax = 0u; +#endif + + p_tcb->PendNextPtr = (OS_TCB *)0; + p_tcb->PendPrevPtr = (OS_TCB *)0; + p_tcb->PendObjPtr = (OS_PEND_OBJ *)0; + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; + p_tcb->PendStatus = OS_STATUS_PEND_OK; + p_tcb->TaskState = OS_TASK_STATE_RDY; + + p_tcb->Prio = OS_PRIO_INIT; +#if (OS_CFG_MUTEX_EN > 0u) + p_tcb->BasePrio = OS_PRIO_INIT; + p_tcb->MutexGrpHeadPtr = (OS_MUTEX *)0; +#endif + +#if (OS_CFG_DBG_EN > 0u) + p_tcb->DbgPrevPtr = (OS_TCB *)0; + p_tcb->DbgNextPtr = (OS_TCB *)0; + p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" "); +#endif +} + + +/* +************************************************************************************************************************ +* CATCH ACCIDENTAL TASK RETURN +* +* Description: This function is called if a task accidentally returns without deleting itself. In other words, a task +* should either be an infinite loop or delete itself if it's done. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_TaskReturn (void) +{ + OS_ERR err; + + + + OSTaskReturnHook(OSTCBCurPtr); /* Call hook to let user decide on what to do */ +#if (OS_CFG_TASK_DEL_EN > 0u) + OSTaskDel((OS_TCB *)0, /* Delete task if it accidentally returns! */ + &err); +#else + for (;;) { + OSTimeDly(OSCfg_TickRate_Hz, + OS_OPT_TIME_DLY, + &err); + } +#endif +} + + +/* +************************************************************************************************************************ +* CHECK THE STACK REDZONE OF A TASK +* +* Description: Verify a task's stack redzone. +* +* Arguments : p_tcb is a pointer to the base of the stack. +* +* stk_size is the size of the stack. +* +* Returns : If the stack is corrupted (OS_FALSE) or not (OS_TRUE). +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +CPU_BOOLEAN OS_TaskStkRedzoneChk (CPU_STK *p_base, + CPU_STK_SIZE stk_size) +{ + CPU_INT32U i; + + +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + (void)stk_size; /* Prevent compiler warning for not using 'stk_size' */ + + for (i = 0u; i < OS_CFG_TASK_STK_REDZONE_DEPTH; i++) { + if (*p_base != (CPU_DATA)OS_STACK_CHECK_VAL) { + return (OS_FALSE); + } + p_base++; + } +#else + p_base = p_base + stk_size - 1u; + for (i = 0u; i < OS_CFG_TASK_STK_REDZONE_DEPTH; i++) { + if (*p_base != (CPU_DATA)OS_STACK_CHECK_VAL) { + return (OS_FALSE); + } + p_base--; + } +#endif + + return (OS_TRUE); +} +#endif + + +/* +************************************************************************************************************************ +* INITIALIZE A REDZONE ENABLED STACK +* +* Description: This functions is used to initialize a stack with Redzone checking. +* +* Arguments : p_tcb is a pointer to the base of the stack. +* +* stk_size is the size of the stack. +* +* Returns : none. +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TASK_STK_REDZONE_EN > 0u) +void OS_TaskStkRedzoneInit (CPU_STK *p_base, + CPU_STK_SIZE stk_size) +{ + CPU_STK_SIZE i; + + +#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) + (void)stk_size; /* Prevent compiler warning for not using 'stk_size' */ + + for (i = 0u; i < OS_CFG_TASK_STK_REDZONE_DEPTH; i++) { + *(p_base + i) = (CPU_DATA)OS_STACK_CHECK_VAL; + } +#else + for (i = 0u; i < OS_CFG_TASK_STK_REDZONE_DEPTH; i++) { + *(p_base + stk_size - 1u - i) = (CPU_DATA)OS_STACK_CHECK_VAL; + } +#endif +} +#endif + + +/* +************************************************************************************************************************ +* CHANGE PRIORITY OF A TASK +* +* Description: This function is called by the kernel to perform the actual operation of changing a task's priority. +* Priority inheritance is updated if necessary. +* +* +* +* Argument(s): p_tcb is a pointer to the tcb of the task to change the priority. +* +* prio_new is the new priority to give to the task. +* +* +* Returns : none. +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TaskChangePrio(OS_TCB *p_tcb, + OS_PRIO prio_new) +{ + OS_TCB *p_tcb_owner; +#if (OS_CFG_MUTEX_EN > 0u) + OS_PRIO prio_cur; +#endif + + + do { + p_tcb_owner = (OS_TCB *)0; +#if (OS_CFG_MUTEX_EN > 0u) + prio_cur = p_tcb->Prio; +#endif + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: + OS_RdyListRemove(p_tcb); /* Remove from current priority */ + p_tcb->Prio = prio_new; /* Set new task priority */ + OS_PrioInsert(p_tcb->Prio); + if (p_tcb == OSTCBCurPtr) { + OS_RdyListInsertHead(p_tcb); + } else { + OS_RdyListInsertTail(p_tcb); + } + break; + + case OS_TASK_STATE_DLY: /* Nothing to do except change the priority in the OS_TCB*/ + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_DLY_SUSPENDED: + p_tcb->Prio = prio_new; /* Set new task priority */ + break; + + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + p_tcb->Prio = prio_new; /* Set new task priority */ + switch (p_tcb->PendOn) { /* What to do depends on what we are pending on */ + case OS_TASK_PEND_ON_FLAG: + case OS_TASK_PEND_ON_Q: + case OS_TASK_PEND_ON_SEM: + OS_PendListChangePrio(p_tcb); + break; + + case OS_TASK_PEND_ON_MUTEX: +#if (OS_CFG_MUTEX_EN > 0u) + OS_PendListChangePrio(p_tcb); + p_tcb_owner = ((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr; + if (prio_cur > prio_new) { /* Are we increasing the priority? */ + if (p_tcb_owner->Prio <= prio_new) { /* Yes, do we need to give this prio to the owner? */ + p_tcb_owner = (OS_TCB *)0; + } else { + /* Block is empty when trace is disabled. */ + OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb_owner, prio_new); + } + } else { + if (p_tcb_owner->Prio == prio_cur) { /* No, is it required to check for a lower prio? */ + prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); + prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new; + if (prio_new == p_tcb_owner->Prio) { + p_tcb_owner = (OS_TCB *)0; + } else { + /* Block is empty when trace is disabled. */ + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, prio_new); + } + } + } +#endif + break; + + case OS_TASK_PEND_ON_TASK_Q: + case OS_TASK_PEND_ON_TASK_SEM: + default: + /* Default case. */ + break; + } + break; + + default: + return; + } + p_tcb = p_tcb_owner; + } while (p_tcb != (OS_TCB *)0); +} diff --git a/rtos/uC-OS3/Source/os_tick.c b/rtos/uC-OS3/Source/os_tick.c new file mode 100644 index 00000000..c4a63ae4 --- /dev/null +++ b/rtos/uC-OS3/Source/os_tick.c @@ -0,0 +1,577 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* TICK MANAGEMENT +* +* File : os_tick.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_tick__c = "$Id: $"; +#endif + +#if (OS_CFG_TICK_EN > 0u) +/* +************************************************************************************************************************ +* FUNCTION PROTOTYPES +************************************************************************************************************************ +*/ + +static void OS_TickListUpdate (OS_TICK ticks); + + +/* +************************************************************************************************************************ +* TICK INIT +* +* Description: This function initializes the variables related to the tick handler. +* The function is internal to uC/OS-III. +* +* Arguments : p_err is a pointer to a variable that will contain an error code returned by this function. +* ----- +* OS_ERR_NONE the tick variables were initialized successfully +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_TickInit (OS_ERR *p_err) +{ + *p_err = OS_ERR_NONE; + + OSTickCtr = 0u; /* Clear the tick counter */ + +#if (OS_CFG_DYN_TICK_EN > 0u) + OSTickCtrStep = 0u; +#endif + + OSTickList.TCB_Ptr = (OS_TCB *)0; + +#if (OS_CFG_DBG_EN > 0u) + OSTickList.NbrEntries = 0u; + OSTickList.NbrUpdated = 0u; +#endif +} + +/* +************************************************************************************************************************ +* TICK UPDATE +* +* Description: This function updates the list of task either delayed pending with timeout. +* The function is internal to uC/OS-III. +* +* Arguments : ticks the number of ticks which have elapsed +* ----- +* +* Returns : none +* +* Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + +void OS_TickUpdate (OS_TICK ticks) +{ +#if (OS_CFG_TS_EN > 0u) + CPU_TS ts_start; +#endif + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); + + OSTickCtr += ticks; /* Keep track of the number of ticks */ + + OS_TRACE_TICK_INCREMENT(OSTickCtr); + +#if (OS_CFG_TS_EN > 0u) + ts_start = OS_TS_GET(); + OS_TickListUpdate(ticks); + OSTickTime = OS_TS_GET() - ts_start; + if (OSTickTimeMax < OSTickTime) { + OSTickTimeMax = OSTickTime; + } +#else + OS_TickListUpdate(ticks); +#endif + +#if (OS_CFG_DYN_TICK_EN > 0u) + if (OSTickList.TCB_Ptr != (OS_TCB *)0) { + OSTickCtrStep = OSTickList.TCB_Ptr->TickRemain; + } else { + OSTickCtrStep = 0u; + } + + OS_DynTickSet(OSTickCtrStep); +#endif + CPU_CRITICAL_EXIT(); +} + +/* +************************************************************************************************************************ +* INSERT +* +* Description: This task is internal to uC/OS-III and allows the insertion of a task in a tick list. +* +* Arguments : p_tcb is a pointer to the TCB to insert in the list +* +* elapsed is the number of elapsed ticks since the last tick interrupt +* +* tick_base is value of OSTickCtr from which time is offset +* +* time is the amount of time remaining (in ticks) for the task to become ready +* +* Returns : OS_TRUE if time is valid for the given tick base +* +* OS_FALSE if time is invalid (i.e. zero delay) +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it. +* +* 2) This function supports both Periodic Tick Mode (PTM) and Dynamic Tick Mode (DTM). +* +* 3) PTM should always call this function with elapsed == 0u. +************************************************************************************************************************ +*/ + +CPU_BOOLEAN OS_TickListInsert (OS_TCB *p_tcb, + OS_TICK elapsed, + OS_TICK tick_base, + OS_TICK time) +{ + OS_TCB *p_tcb1; + OS_TCB *p_tcb2; + OS_TICK_LIST *p_list; + OS_TICK delta; + OS_TICK remain; + + + delta = (time + tick_base) - (OSTickCtr + elapsed); /* How many ticks until our delay expires? */ + + if (delta == 0u) { + p_tcb->TickRemain = 0u; + return (OS_FALSE); + } + + OS_TRACE_TASK_DLY(delta); + + p_list = &OSTickList; + if (p_list->TCB_Ptr == (OS_TCB *)0) { /* Is the list empty? */ + p_tcb->TickRemain = delta; /* Yes, Store time in TCB */ + p_tcb->TickNextPtr = (OS_TCB *)0; + p_tcb->TickPrevPtr = (OS_TCB *)0; + p_list->TCB_Ptr = p_tcb; /* Point to TCB of task to place in the list */ +#if (OS_CFG_DYN_TICK_EN > 0u) + if (elapsed != 0u) { + OSTickCtr += elapsed; /* Update OSTickCtr before we set a new tick step. */ + OS_TRACE_TICK_INCREMENT(OSTickCtr); + } + + OSTickCtrStep = delta; + OS_DynTickSet(OSTickCtrStep); +#endif +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries = 1u; /* List contains 1 entry */ +#endif + return (OS_TRUE); + } + + +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries++; /* Update debug counter to reflect the new entry. */ +#endif + + p_tcb2 = p_list->TCB_Ptr; + remain = p_tcb2->TickRemain - elapsed; /* How many ticks until the head's delay expires? */ + + if ((delta < remain) && /* If our entry is the new head of the tick list ... */ + (p_tcb2->TickPrevPtr == (OS_TCB *)0)) { + p_tcb->TickRemain = delta; /* ... the delta is equivalent to the full delay ... */ + p_tcb2->TickRemain = remain - delta; /* ... the previous head's delta is now relative to it. */ + + p_tcb->TickPrevPtr = (OS_TCB *)0; + p_tcb->TickNextPtr = p_tcb2; + p_tcb2->TickPrevPtr = p_tcb; + p_list->TCB_Ptr = p_tcb; +#if (OS_CFG_DYN_TICK_EN > 0u) + if (elapsed != 0u) { + OSTickCtr += elapsed; /* Update OSTickCtr before we set a new tick step. */ + OS_TRACE_TICK_INCREMENT(OSTickCtr); + } + /* In DTM, a new list head must update the tick ... */ + OSTickCtrStep = delta; /* ... timer to interrupt at the new delay value. */ + OS_DynTickSet(OSTickCtrStep); +#endif + + return (OS_TRUE); + } + + /* Our entry comes after the current list head. */ + delta -= remain; /* Make delta relative to the head. */ + p_tcb1 = p_tcb2; + p_tcb2 = p_tcb1->TickNextPtr; + + while ((p_tcb2 != (OS_TCB *)0) && /* Find the appropriate position in the delta list. */ + (delta >= p_tcb2->TickRemain)) { + delta -= p_tcb2->TickRemain; + p_tcb1 = p_tcb2; + p_tcb2 = p_tcb2->TickNextPtr; + } + + if (p_tcb2 != (OS_TCB *)0) { /* Our entry is not the last element in the list. */ + p_tcb1 = p_tcb2->TickPrevPtr; + p_tcb->TickRemain = delta; /* Store remaining time */ + p_tcb->TickPrevPtr = p_tcb1; + p_tcb->TickNextPtr = p_tcb2; + p_tcb2->TickRemain -= delta; /* Reduce time of next entry in the list */ + p_tcb2->TickPrevPtr = p_tcb; + p_tcb1->TickNextPtr = p_tcb; + + } else { /* Our entry belongs at the end of the list. */ + p_tcb->TickRemain = delta; + p_tcb->TickPrevPtr = p_tcb1; + p_tcb->TickNextPtr = (OS_TCB *)0; + p_tcb1->TickNextPtr = p_tcb; + } + + return (OS_TRUE); +} + +/* +************************************************************************************************************************ +* ADD DELAYED TASK TO TICK LIST +* +* Description: This function is called to place a task in a list of task waiting for time to expire +* +* Arguments : p_tcb is a pointer to the OS_TCB of the task to add to the tick list +* ----- +* +* time represents either the 'match' value of OSTickCtr or a relative time from the current +* system time as specified by the 'opt' argument.. +* +* relative when 'opt' is set to OS_OPT_TIME_DLY +* relative when 'opt' is set to OS_OPT_TIME_TIMEOUT +* match when 'opt' is set to OS_OPT_TIME_MATCH +* periodic when 'opt' is set to OS_OPT_TIME_PERIODIC +* +* opt is an option specifying how to calculate time. The valid values are: +* --- +* OS_OPT_TIME_DLY +* OS_OPT_TIME_TIMEOUT +* OS_OPT_TIME_PERIODIC +* OS_OPT_TIME_MATCH +* +* p_err is a pointer to a variable that will contain an error code returned by this function. +* ----- +* OS_ERR_NONE the call was successful and the time delay was scheduled. +* OS_ERR_TIME_ZERO_DLY if the effective delay is zero +* +* Returns : None +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +* +* 2) This function is assumed to be called with interrupts disabled. +************************************************************************************************************************ +*/ + +void OS_TickListInsertDly (OS_TCB *p_tcb, + OS_TICK time, + OS_OPT opt, + OS_ERR *p_err) +{ + OS_TICK elapsed; + OS_TICK tick_base; + OS_TICK base_offset; + CPU_BOOLEAN valid_dly; + + +#if (OS_CFG_DYN_TICK_EN > 0u) + elapsed = OS_DynTickGet(); +#else + elapsed = 0u; +#endif + + if (opt == OS_OPT_TIME_MATCH) { /* MATCH to absolute tick ctr value mode */ + tick_base = 0u; /* tick_base + time == time */ + + } else if (opt == OS_OPT_TIME_PERIODIC) { /* PERIODIC mode. */ + if (time == 0u) { + *p_err = OS_ERR_TIME_ZERO_DLY; /* Infinite frequency is invalid. */ + return; + } + + tick_base = p_tcb->TickCtrPrev; + +#if (OS_CFG_DYN_TICK_EN > 0u) /* How far is our tick-base from the system time? */ + base_offset = OSTickCtr + elapsed - tick_base; +#else + base_offset = OSTickCtr - tick_base; +#endif + + if (base_offset >= time) { /* If our task missed the last period, move ... */ + tick_base += time * (base_offset / time); /* ... tick_base up to the next one. */ + if ((base_offset % time) != 0u) { + tick_base += time; /* Account for rounding errors with integer division */ + } + + p_tcb->TickCtrPrev = tick_base; /* Adjust the periodic tick base */ + } + + p_tcb->TickCtrPrev += time; /* Update for the next time we perform a periodic dly. */ + + } else { /* RELATIVE time delay mode */ +#if (OS_CFG_DYN_TICK_EN > 0u) /* Our base is always the current system time. */ + tick_base = OSTickCtr + elapsed; +#else + tick_base = OSTickCtr; +#endif + } + + valid_dly = OS_TickListInsert(p_tcb, elapsed, tick_base, time); + + if (valid_dly == OS_TRUE) { + p_tcb->TaskState = OS_TASK_STATE_DLY; + *p_err = OS_ERR_NONE; + } else { + *p_err = OS_ERR_TIME_ZERO_DLY; + } +} + +/* +************************************************************************************************************************ +* REMOVE A TASK FROM THE TICK LIST +* +* Description: This function is called to remove a task from the tick list +* +* Arguments : p_tcb Is a pointer to the OS_TCB to remove. +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +* +* 2) This function is assumed to be called with interrupts disabled. +************************************************************************************************************************ +*/ + +void OS_TickListRemove (OS_TCB *p_tcb) +{ + OS_TCB *p_tcb1; + OS_TCB *p_tcb2; + OS_TICK_LIST *p_list; +#if (OS_CFG_DYN_TICK_EN > 0u) + OS_TICK elapsed; +#endif + +#if (OS_CFG_DYN_TICK_EN > 0u) + elapsed = OS_DynTickGet(); +#endif + + p_tcb1 = p_tcb->TickPrevPtr; + p_tcb2 = p_tcb->TickNextPtr; + p_list = &OSTickList; + if (p_tcb1 == (OS_TCB *)0) { + if (p_tcb2 == (OS_TCB *)0) { /* Remove the ONLY entry in the list? */ + p_list->TCB_Ptr = (OS_TCB *)0; +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries = 0u; +#endif + p_tcb->TickRemain = 0u; +#if (OS_CFG_DYN_TICK_EN > 0u) + if (elapsed != 0u) { + OSTickCtr += elapsed; /* Keep track of time. */ + OS_TRACE_TICK_INCREMENT(OSTickCtr); + } + OSTickCtrStep = 0u; + OS_DynTickSet(OSTickCtrStep); +#endif + } else { + p_tcb2->TickPrevPtr = (OS_TCB *)0; + p_tcb2->TickRemain += p_tcb->TickRemain; /* Add back the ticks to the delta */ + p_list->TCB_Ptr = p_tcb2; +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries--; +#endif + +#if (OS_CFG_DYN_TICK_EN > 0u) + if (p_tcb2->TickRemain != p_tcb->TickRemain) { /* Only set a new tick if tcb2 had a longer delay. */ + if (elapsed != 0u) { + OSTickCtr += elapsed; /* Keep track of time. */ + OS_TRACE_TICK_INCREMENT(OSTickCtr); + p_tcb2->TickRemain -= elapsed; /* We must account for any time which has passed. */ + } + OSTickCtrStep = p_tcb2->TickRemain; + OS_DynTickSet(OSTickCtrStep); + } +#endif + p_tcb->TickNextPtr = (OS_TCB *)0; + p_tcb->TickRemain = 0u; + } + } else { + p_tcb1->TickNextPtr = p_tcb2; + if (p_tcb2 != (OS_TCB *)0) { + p_tcb2->TickPrevPtr = p_tcb1; + p_tcb2->TickRemain += p_tcb->TickRemain; /* Add back the ticks to the delta list */ + } + p_tcb->TickPrevPtr = (OS_TCB *)0; +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries--; +#endif + p_tcb->TickNextPtr = (OS_TCB *)0; + p_tcb->TickRemain = 0u; + } +} + +/* +************************************************************************************************************************ +* UPDATE THE LIST OF TASKS DELAYED OR PENDING WITH TIMEOUT +* +* Description: This function updates the delta list which contains tasks that are delayed or pending with a timeout. +* +* Arguments : ticks the number of ticks which have elapsed. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +static void OS_TickListUpdate (OS_TICK ticks) +{ + OS_TCB *p_tcb; + OS_TICK_LIST *p_list; +#if (OS_CFG_DBG_EN > 0u) + OS_OBJ_QTY nbr_updated; +#endif +#if (OS_CFG_MUTEX_EN > 0u) + OS_TCB *p_tcb_owner; + OS_PRIO prio_new; +#endif + + + +#if (OS_CFG_DBG_EN > 0u) + nbr_updated = 0u; +#endif + p_list = &OSTickList; + p_tcb = p_list->TCB_Ptr; + if (p_tcb != (OS_TCB *)0) { + if (p_tcb->TickRemain <= ticks) { + ticks = ticks - p_tcb->TickRemain; + p_tcb->TickRemain = 0u; + } else { + p_tcb->TickRemain -= ticks; + } + + while (p_tcb->TickRemain == 0u) { +#if (OS_CFG_DBG_EN > 0u) + nbr_updated++; +#endif + + switch (p_tcb->TaskState) { + case OS_TASK_STATE_DLY: + p_tcb->TaskState = OS_TASK_STATE_RDY; + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + break; + + case OS_TASK_STATE_DLY_SUSPENDED: + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; + break; + + default: +#if (OS_CFG_MUTEX_EN > 0u) + p_tcb_owner = (OS_TCB *)0; + if (p_tcb->PendOn == OS_TASK_PEND_ON_MUTEX) { + p_tcb_owner = (OS_TCB *)((OS_MUTEX *)((void *)p_tcb->PendObjPtr))->OwnerTCBPtr; + } +#endif + +#if (OS_MSG_EN > 0u) + p_tcb->MsgPtr = (void *)0; + p_tcb->MsgSize = 0u; +#endif +#if (OS_CFG_TS_EN > 0u) + p_tcb->TS = OS_TS_GET(); +#endif + OS_PendListRemove(p_tcb); /* Remove task from pend list */ + + switch (p_tcb->TaskState) { + case OS_TASK_STATE_PEND_TIMEOUT: + OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */ + p_tcb->TaskState = OS_TASK_STATE_RDY; + break; + + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; + break; + + default: + break; + } + p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */ + p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */ + +#if (OS_CFG_MUTEX_EN > 0u) + if (p_tcb_owner != (OS_TCB *)0) { + if ((p_tcb_owner->Prio != p_tcb_owner->BasePrio) && + (p_tcb_owner->Prio == p_tcb->Prio)) { /* Has the owner inherited a priority? */ + prio_new = OS_MutexGrpPrioFindHighest(p_tcb_owner); + prio_new = (prio_new > p_tcb_owner->BasePrio) ? p_tcb_owner->BasePrio : prio_new; + if (prio_new != p_tcb_owner->Prio) { + OS_TaskChangePrio(p_tcb_owner, prio_new); + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb_owner, p_tcb_owner->Prio); + } + } + } +#endif + break; + } + + p_list->TCB_Ptr = p_tcb->TickNextPtr; + p_tcb = p_list->TCB_Ptr; /* Get 'p_tcb' again for loop */ + if (p_tcb == (OS_TCB *)0) { +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries = 0u; +#endif + break; + } else { +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrEntries--; +#endif + p_tcb->TickPrevPtr = (OS_TCB *)0; + if (p_tcb->TickRemain <= ticks) { + ticks = ticks - p_tcb->TickRemain; + p_tcb->TickRemain = 0u; + } else { + p_tcb->TickRemain -= ticks; + } + } + } + } +#if (OS_CFG_DBG_EN > 0u) + p_list->NbrUpdated = nbr_updated; +#endif +} + +#endif /* #if OS_CFG_TICK_EN */ + diff --git a/rtos/uC-OS3/Source/os_time.c b/rtos/uC-OS3/Source/os_time.c new file mode 100644 index 00000000..8ade4211 --- /dev/null +++ b/rtos/uC-OS3/Source/os_time.c @@ -0,0 +1,600 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* TIME MANAGEMENT +* +* File : os_time.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_time__c = "$Id: $"; +#endif + +/* +************************************************************************************************************************ +* DELAY TASK 'n' TICKS +* +* Description: This function is called to delay execution of the currently running task until the specified number of +* system ticks expires. This, of course, directly equates to delaying the current task for some time to +* expire. No delay will result if the specified delay is 0. If the specified delay is greater than 0 +* then, a context switch will result. +* +* Arguments : dly is a value in 'clock ticks' that the task will either delay for or, the target match value +* of the tick counter (OSTickCtr). Note that specifying 0 means the task is not to delay. +* +* depending on the option argument, the task will wake up when OSTickCtr reaches: +* +* OS_OPT_TIME_DLY : OSTickCtr + dly +* OS_OPT_TIME_TIMEOUT : OSTickCtr + dly +* OS_OPT_TIME_MATCH : dly +* OS_OPT_TIME_PERIODIC : OSTCBCurPtr->TickCtrPrev + dly +* +* opt specifies whether 'dly' represents absolute or relative time; default option marked with *** : +* +* *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr. +* OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY. +* OS_OPT_TIME_MATCH indicates that 'dly' specifies the absolute value that OSTickCtr +* must reach before the task will be resumed. +* OS_OPT_TIME_PERIODIC indicates that 'dly' specifies the periodic value that OSTickCtr +* must reach before the task will be resumed. +* +* p_err is a pointer to a variable that will contain an error code from this call. +* +* OS_ERR_NONE The call was successful and the delay occurred +* OS_ERR_OPT_INVALID If you specified an invalid option for this function +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked +* OS_ERR_TIME_DLY_ISR If you called this function from an ISR +* OS_ERR_TIME_ZERO_DLY If the effective delay is zero +* OS_ERR_TICK_DISABLED If kernel ticks are disabled +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSTimeDly (OS_TICK dly, + OS_OPT opt, + OS_ERR *p_err) +{ +#if (OS_CFG_TICK_EN > 0u) + CPU_SR_ALLOC(); +#endif + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_TICK_EN == 0u) + *p_err = OS_ERR_TICK_DISABLED; + return; +#else + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TIME_DLY_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + + if (OSSchedLockNestingCtr > 0u) { /* Can't delay when the scheduler is locked */ + *p_err = OS_ERR_SCHED_LOCKED; + return; + } + + switch (opt) { + case OS_OPT_TIME_DLY: + case OS_OPT_TIME_TIMEOUT: + case OS_OPT_TIME_PERIODIC: + case OS_OPT_TIME_MATCH: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return; + } + +#if (OS_CFG_TICK_EN > 0u) + CPU_CRITICAL_ENTER(); + OS_TickListInsertDly(OSTCBCurPtr, + dly, + opt, + p_err); + if (*p_err != OS_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } + + OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */ + CPU_CRITICAL_EXIT(); + OSSched(); /* Find next task to run! */ +#endif +#endif +} + + +/* +************************************************************************************************************************ +* DELAY TASK FOR SPECIFIED TIME +* +* Description: This function is called to delay execution of the currently running task until some time expires. This +* call allows you to specify the delay time in HOURS, MINUTES, SECONDS and MILLISECONDS instead of ticks. +* +* Arguments : hours specifies the number of hours that the task will be delayed (max. is 999 if the tick rate is +* 1000 Hz or less otherwise, a higher value would overflow a 32-bit unsigned counter). +* +* minutes specifies the number of minutes (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT) +* +* seconds specifies the number of seconds (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT) +* +* milli specifies the number of milliseconds (max. 999 if 'opt' is OS_OPT_TIME_HMSM_STRICT) +* +* opt specifies time delay bit-field options logically OR'd; default options marked with *** : +* +* *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr. +* OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY. +* OS_OPT_TIME_MATCH indicates that the delay specifies the absolute value that OSTickCtr +* must reach before the task will be resumed. +* OS_OPT_TIME_PERIODIC indicates that the delay specifies the periodic value that OSTickCtr +* must reach before the task will be resumed. +* +* *** OS_OPT_TIME_HMSM_STRICT strictly allow only hours (0...99) +* minutes (0...59) +* seconds (0...59) +* milliseconds (0...999) +* OS_OPT_TIME_HMSM_NON_STRICT allow any value of hours (0...999) +* minutes (0...9999) +* seconds (0...65535) +* milliseconds (0...4294967295) +* +* p_err is a pointer to a variable that will receive an error code from this call. +* +* OS_ERR_NONE If the function returns from the desired delay +* OS_ERR_OPT_INVALID If you specified an invalid option for 'opt' +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked +* OS_ERR_TIME_DLY_ISR If called from an ISR +* OS_ERR_TIME_INVALID_HOURS If you didn't specify a valid value for 'hours' +* OS_ERR_TIME_INVALID_MINUTES If you didn't specify a valid value for 'minutes' +* OS_ERR_TIME_INVALID_SECONDS If you didn't specify a valid value for 'seconds' +* OS_ERR_TIME_INVALID_MILLISECONDS If you didn't specify a valid value for 'milli' +* OS_ERR_TIME_ZERO_DLY If the effective delay is zero +* OS_ERR_TICK_DISABLED If kernel ticks are disabled +* +* Returns : none +* +* Note(s) : 1) The resolution on the milliseconds depends on the tick rate. For example, you can't do a 10 mS delay +* if the ticker interrupts every 100 mS. In this case, the delay would be set to 0. The actual delay +* is rounded to the nearest tick. +* +* 2) Although this function allows you to delay a task for many, many hours, it's not recommended to put +* a task to sleep for that long. +************************************************************************************************************************ +*/ + +#if (OS_CFG_TIME_DLY_HMSM_EN > 0u) +void OSTimeDlyHMSM (CPU_INT16U hours, + CPU_INT16U minutes, + CPU_INT16U seconds, + CPU_INT32U milli, + OS_OPT opt, + OS_ERR *p_err) +{ +#if (OS_CFG_TICK_EN > 0u) +#if (OS_CFG_ARG_CHK_EN > 0u) + CPU_BOOLEAN opt_invalid; + CPU_BOOLEAN opt_non_strict; +#endif + OS_OPT opt_time; + OS_RATE_HZ tick_rate; + OS_TICK ticks; + CPU_SR_ALLOC(); +#endif + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_TICK_EN == 0u) + *p_err = OS_ERR_TICK_DISABLED; + return; +#else +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TIME_DLY_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + + if (OSSchedLockNestingCtr > 0u) { /* Can't delay when the scheduler is locked */ + *p_err = OS_ERR_SCHED_LOCKED; + return; + } + + opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */ + switch (opt_time) { + case OS_OPT_TIME_DLY: + case OS_OPT_TIME_TIMEOUT: + case OS_OPT_TIME_PERIODIC: + case OS_OPT_TIME_MATCH: + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return; + } + +#if (OS_CFG_ARG_CHK_EN > 0u) /* Validate arguments to be within range */ + opt_invalid = ((((opt) & (~OS_OPT_TIME_OPTS_MASK)) == 0u) ? (OS_FALSE) : (OS_TRUE)); + if (opt_invalid == OS_TRUE) { + *p_err = OS_ERR_OPT_INVALID; + return; + } + + opt_non_strict = ((((opt) & (OS_OPT_TIME_HMSM_NON_STRICT)) == 0u) ? (OS_FALSE) : (OS_TRUE)); + + if (opt_non_strict != OS_TRUE) { + if (milli > 999u) { + *p_err = OS_ERR_TIME_INVALID_MILLISECONDS; + return; + } + if (seconds > 59u) { + *p_err = OS_ERR_TIME_INVALID_SECONDS; + return; + } + if (minutes > 59u) { + *p_err = OS_ERR_TIME_INVALID_MINUTES; + return; + } + if (hours > 99u) { + *p_err = OS_ERR_TIME_INVALID_HOURS; + return; + } + } else { + if (minutes > 9999u) { + *p_err = OS_ERR_TIME_INVALID_MINUTES; + return; + } + if (hours > 999u) { + *p_err = OS_ERR_TIME_INVALID_HOURS; + return; + } + } +#endif + + /* Compute the total number of clock ticks required.. */ + /* .. (rounded to the nearest tick) */ + tick_rate = OSCfg_TickRate_Hz; + ticks = ((((OS_TICK)hours * (OS_TICK)3600u) + ((OS_TICK)minutes * (OS_TICK)60u) + (OS_TICK)seconds) * tick_rate) + + ((tick_rate * ((OS_TICK)milli + ((OS_TICK)500u / tick_rate))) / (OS_TICK)1000u); + + + CPU_CRITICAL_ENTER(); + OS_TickListInsertDly(OSTCBCurPtr, + ticks, + opt_time, + p_err); + if (*p_err != OS_ERR_NONE) { + CPU_CRITICAL_EXIT(); + return; + } + + OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */ + CPU_CRITICAL_EXIT(); + OSSched(); /* Find next task to run! */ +#endif +} +#endif + +/* +************************************************************************************************************************ +* RESUME A DELAYED TASK +* +* Description: This function is used resume a task that has been delayed through a call to either OSTimeDly() or +* OSTimeDlyHMSM(). Note that you cannot call this function to resume a task that is waiting for an event +* with timeout. +* +* Arguments : p_tcb is a pointer to the TCB of the task to resume. +* +* p_err is a pointer to a variable that will receive an error code +* +* OS_ERR_NONE Task has been resumed +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_STATE_INVALID Task is in an invalid state +* OS_ERR_TASK_NOT_DLY Task is not waiting for time to expire +* OS_ERR_TASK_SUSPENDED Task cannot be resumed, it was suspended by OSTaskSuspend() +* OS_ERR_TCB_INVALID If 'p_tcb' is a NULL pointer +* OS_ERR_TIME_DLY_RESUME_ISR If called from an ISR +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TIME_DLY_RESUME_EN > 0u) +void OSTimeDlyResume (OS_TCB *p_tcb, + OS_ERR *p_err) +{ + CPU_SR_ALLOC(); + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */ + *p_err = OS_ERR_TIME_DLY_RESUME_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) /* ---------------- VALIDATE ARGUMENTS ---------------- */ + if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */ + *p_err = OS_ERR_TCB_INVALID; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + + CPU_CRITICAL_ENTER(); + switch (p_tcb->TaskState) { + case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */ + case OS_TASK_STATE_PEND: + case OS_TASK_STATE_PEND_TIMEOUT: + case OS_TASK_STATE_SUSPENDED: + case OS_TASK_STATE_PEND_SUSPENDED: + case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_NOT_DLY; + break; + + case OS_TASK_STATE_DLY: + p_tcb->TaskState = OS_TASK_STATE_RDY; +#if (OS_CFG_TICK_EN > 0u) + OS_TickListRemove(p_tcb); /* Remove task from tick list */ + OS_RdyListInsert(p_tcb); /* Add to ready list */ +#endif + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; + break; + + case OS_TASK_STATE_DLY_SUSPENDED: + p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; +#if (OS_CFG_TICK_EN > 0u) + OS_TickListRemove(p_tcb); /* Remove task from tick list */ +#endif + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_TASK_SUSPENDED; + break; + + default: + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_STATE_INVALID; + break; + } + + OSSched(); +} +#endif + +/* +************************************************************************************************************************ +* GET CURRENT SYSTEM TIME +* +* Description: This function is used by your application to obtain the current value of the counter which keeps track of +* the number of clock ticks. +* +* Arguments : p_err is a pointer to a variable that will receive an error code +* +* OS_ERR_NONE If the call was successful +* OS_ERR_TICK_DISABLED If kernel ticks are disabled +* +* Returns : The current value of OSTickCtr +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_TICK OSTimeGet (OS_ERR *p_err) +{ + OS_TICK ticks; +#if (OS_CFG_TICK_EN > 0u) + CPU_SR_ALLOC(); +#endif + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + + +#if (OS_CFG_TICK_EN > 0u) + CPU_CRITICAL_ENTER(); +#if (OS_CFG_DYN_TICK_EN > 0u) + if (OSRunning == OS_STATE_OS_RUNNING) { + ticks = OSTickCtr + OS_DynTickGet(); + } else { + ticks = OSTickCtr; + } +#else + ticks = OSTickCtr; +#endif + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +#else + ticks = 0u; + *p_err = OS_ERR_TICK_DISABLED; +#endif + + return (ticks); +} + +/* +************************************************************************************************************************ +* SET SYSTEM CLOCK +* +* Description: This function sets the counter which keeps track of the number of clock ticks. +* +* Arguments : ticks is the desired tick value +* +* p_err is a pointer to a variable that will receive an error code +* +* OS_ERR_NONE If the call was successful +* OS_ERR_TICK_DISABLED If kernel ticks are disabled +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSTimeSet (OS_TICK ticks, + OS_ERR *p_err) +{ +#if (OS_CFG_TICK_EN > 0u) + CPU_SR_ALLOC(); + +#else + (void)ticks; +#endif + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_TICK_EN > 0u) + CPU_CRITICAL_ENTER(); + OSTickCtr = ticks; + OS_TRACE_TICK_INCREMENT(OSTickCtr); + CPU_CRITICAL_EXIT(); + *p_err = OS_ERR_NONE; +#else + *p_err = OS_ERR_TICK_DISABLED; +#endif + +} + + +/* +************************************************************************************************************************ +* PROCESS SYSTEM TICK +* +* Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a +* 'clock tick'). This function should be called by the tick ISR. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +void OSTimeTick (void) +{ + if (OSRunning != OS_STATE_OS_RUNNING) { + return; + } + + OSTimeTickHook(); /* Call user definable hook */ + +#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u) + OS_SchedRoundRobin(&OSRdyList[OSPrioCur]); /* Update quanta ctr for the task which just ran */ +#endif + +#if (OS_CFG_TICK_EN > 0u) + OS_TickUpdate(1u); /* Update from the ISR */ +#endif +} + + +/* +************************************************************************************************************************ +* PROCESS SYSTEM TICK (DYNAMIC) +* +* Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a +* 'clock tick'). This function should be called by the tick ISR. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_DYN_TICK_EN > 0u) +void OSTimeDynTick (OS_TICK ticks) +{ + if (OSRunning != OS_STATE_OS_RUNNING) { + return; + } + + OSTimeTickHook(); + + OS_TickUpdate(ticks); /* Update from the ISR */ +} +#endif diff --git a/rtos/uC-OS3/Source/os_tmr.c b/rtos/uC-OS3/Source/os_tmr.c new file mode 100644 index 00000000..b8b755ad --- /dev/null +++ b/rtos/uC-OS3/Source/os_tmr.c @@ -0,0 +1,1657 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* TIMER MANAGEMENT +* +* File : os_tmr.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_tmr__c = "$Id: $"; +#endif + + +#if (OS_CFG_TMR_EN > 0u) +/* +************************************************************************************************************************ +* LOCAL FUNCTION PROTOTYPES +************************************************************************************************************************ +*/ + +static void OS_TmrLock (void); +static void OS_TmrUnlock (void); + +static void OS_TmrCondCreate(void); +static void OS_TmrCondSignal(void); +static void OS_TmrCondWait (OS_TICK timeout); + + +/* +************************************************************************************************************************ +* CREATE A TIMER +* +* Description: This function is called by your application code to create a timer. +* +* Arguments : p_tmr Is a pointer to a timer control block +* +* p_name Is a pointer to an ASCII string that is used to name the timer. Names are useful for +* debugging. +* +* dly Initial delay. +* If the timer is configured for ONE-SHOT mode, this is the timeout used +* If the timer is configured for PERIODIC mode, this is the first timeout to wait for +* before the timer starts entering periodic mode +* +* period The 'period' being repeated for the timer. +* If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will +* automatically restart with the same period. +* +* opt Specifies either: +* +* OS_OPT_TMR_ONE_SHOT The timer counts down only once +* OS_OPT_TMR_PERIODIC The timer counts down and then reloads itself +* +* p_callback Is a pointer to a callback function that will be called when the timer expires. The +* callback function must be declared as follows: +* +* void MyCallback (OS_TMR *p_tmr, void *p_arg); +* +* p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called. +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The call succeeded +* OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the timer after you called +* OSSafetyCriticalStart() +* OS_ERR_OBJ_PTR_NULL Is 'p_tmr' is a NULL pointer +* OS_ERR_OPT_INVALID You specified an invalid option +* OS_ERR_TMR_INVALID_CALLBACK You specified an invalid callback for a periodic timer +* OS_ERR_TMR_INVALID_DLY You specified an invalid delay +* OS_ERR_TMR_INVALID_PERIOD You specified an invalid period +* OS_ERR_TMR_ISR If the call was made from an ISR +* OS_ERR_OBJ_CREATED If the timer was already created +* +* Returns : none +* +* Note(s) : 1) This function only creates the timer. In other words, the timer is not started when created. To +* start the timer, call OSTmrStart(). +************************************************************************************************************************ +*/ + +void OSTmrCreate (OS_TMR *p_tmr, + CPU_CHAR *p_name, + OS_TICK dly, + OS_TICK period, + OS_OPT opt, + OS_TMR_CALLBACK_PTR p_callback, + void *p_callback_arg, + OS_ERR *p_err) +{ +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */ + *p_err = OS_ERR_OBJ_PTR_NULL; + return; + } + + switch (opt) { + case OS_OPT_TMR_PERIODIC: + if (period == 0u) { + *p_err = OS_ERR_TMR_INVALID_PERIOD; + return; + } + + if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */ + *p_err = OS_ERR_TMR_INVALID_CALLBACK; + return; + } + break; + + case OS_OPT_TMR_ONE_SHOT: + if (dly == 0u) { + *p_err = OS_ERR_TMR_INVALID_DLY; + return; + } + break; + + default: + *p_err = OS_ERR_OPT_INVALID; + return; + } +#endif + + if (OSRunning == OS_STATE_OS_RUNNING) { /* Only lock when the kernel is running */ + OS_TmrLock(); + } + + p_tmr->State = OS_TMR_STATE_STOPPED; /* Initialize the timer fields */ +#if (OS_OBJ_TYPE_REQ > 0u) + if (p_tmr->Type == OS_OBJ_TYPE_TMR) { + if (OSRunning == OS_STATE_OS_RUNNING) { + OS_TmrUnlock(); + } + *p_err = OS_ERR_OBJ_CREATED; + return; + } + p_tmr->Type = OS_OBJ_TYPE_TMR; +#endif +#if (OS_CFG_DBG_EN > 0u) + p_tmr->NamePtr = p_name; +#else + (void)p_name; +#endif + p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert to Timer Start Delay to ticks */ + p_tmr->Remain = 0u; + p_tmr->Period = period * OSTmrToTicksMult; /* Convert to Timer Period to ticks */ + p_tmr->Opt = opt; + p_tmr->CallbackPtr = p_callback; + p_tmr->CallbackPtrArg = p_callback_arg; + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr->PrevPtr = (OS_TMR *)0; + +#if (OS_CFG_DBG_EN > 0u) + OS_TmrDbgListAdd(p_tmr); +#endif +#if (OS_CFG_DBG_EN > 0u) + OSTmrQty++; /* Keep track of the number of timers created */ +#endif + + if (OSRunning == OS_STATE_OS_RUNNING) { + OS_TmrUnlock(); + } + + *p_err = OS_ERR_NONE; +} + + +/* +************************************************************************************************************************ +* DELETE A TIMER +* +* Description: This function is called by your application code to delete a timer. +* +* Arguments : p_tmr Is a pointer to the timer to stop and delete. +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The call succeeded +* OS_ERR_ILLEGAL_DEL_RUN_TIME If you are trying to delete the timer after you called +* OSStart() +* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INACTIVE If the timer was not created +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer +* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state +* OS_ERR_TMR_ISR If the function was called from an ISR +* +* Returns : OS_TRUE if the timer was deleted +* OS_FALSE if not or upon an error +* +* Note(s) : none +************************************************************************************************************************ +*/ + +#if (OS_CFG_TMR_DEL_EN > 0u) +CPU_BOOLEAN OSTmrDel (OS_TMR *p_tmr, + OS_ERR *p_err) +{ + CPU_BOOLEAN success; + OS_TICK time; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#ifdef OS_SAFETY_CRITICAL_IEC61508 + if (OSSafetyCriticalStartFlag == OS_TRUE) { + *p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { + *p_err = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (OS_FALSE); + } +#endif + + OS_TmrLock(); + + CPU_CRITICAL_ENTER(); + if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */ + time = OSTmrTaskTickBase; + } else { +#if (OS_CFG_DYN_TICK_EN > 0u) + time = OSTickCtr + OS_DynTickGet(); +#else + time = OSTickCtr; +#endif + } + CPU_CRITICAL_EXIT(); + +#if (OS_CFG_DBG_EN > 0u) + OS_TmrDbgListRemove(p_tmr); +#endif + + switch (p_tmr->State) { + case OS_TMR_STATE_RUNNING: + case OS_TMR_STATE_TIMEOUT: + OS_TmrUnlink(p_tmr, time); /* Remove from the list */ + OS_TmrClr(p_tmr); +#if (OS_CFG_DBG_EN > 0u) + OSTmrQty--; /* One less timer */ +#endif + *p_err = OS_ERR_NONE; + success = OS_TRUE; + break; + + case OS_TMR_STATE_STOPPED: /* Timer has not started or ... */ + case OS_TMR_STATE_COMPLETED: /* ... timer has completed the ONE-SHOT time */ + OS_TmrClr(p_tmr); /* Clear timer fields */ +#if (OS_CFG_DBG_EN > 0u) + OSTmrQty--; /* One less timer */ +#endif + *p_err = OS_ERR_NONE; + success = OS_TRUE; + break; + + case OS_TMR_STATE_UNUSED: /* Already deleted */ + *p_err = OS_ERR_TMR_INACTIVE; + success = OS_FALSE; + break; + + default: + *p_err = OS_ERR_TMR_INVALID_STATE; + success = OS_FALSE; + break; + } + + OS_TmrUnlock(); + + return (success); +} +#endif + + +/* +************************************************************************************************************************ +* GET HOW MUCH TIME IS LEFT BEFORE A TIMER EXPIRES +* +* Description: This function is called to get the number of timer increments before a timer times out. +* +* Arguments : p_tmr Is a pointer to the timer to obtain the remaining time from. +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The call succeeded +* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INACTIVE If 'p_tmr' points to a timer that is not active +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer +* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state +* OS_ERR_TMR_ISR If the call was made from an ISR +* +* Returns : The time remaining for the timer to expire. The time represents 'timer' increments (typically 1/10 sec). +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_TICK OSTmrRemainGet (OS_TMR *p_tmr, + OS_ERR *p_err) +{ + OS_TMR *p_tmr1; + OS_TICK remain; + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (0u); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return (0u); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (0u); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { + *p_err = OS_ERR_TMR_INVALID; + return (0u); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (0u); + } +#endif + + OS_TmrLock(); + + switch (p_tmr->State) { + case OS_TMR_STATE_RUNNING: + p_tmr1 = OSTmrListPtr; + remain = 0u; + while (p_tmr1 != (OS_TMR *)0) { /* Add up all the deltas up until the current timer */ + remain += p_tmr1->Remain; + if (p_tmr1 == p_tmr) { + break; + } + p_tmr1 = p_tmr1->NextPtr; + } + remain /= OSTmrToTicksMult; + *p_err = OS_ERR_NONE; + break; + + case OS_TMR_STATE_STOPPED: /* It's assumed that the timer has not started yet */ + if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) { + if (p_tmr->Dly == 0u) { + remain = p_tmr->Period / OSTmrToTicksMult; + } else { + remain = p_tmr->Dly / OSTmrToTicksMult; + } + } else { + remain = p_tmr->Dly / OSTmrToTicksMult; + } + *p_err = OS_ERR_NONE; + break; + + case OS_TMR_STATE_TIMEOUT: /* Within a callback, timers are in the TIMEOUT state */ + case OS_TMR_STATE_COMPLETED: /* Only ONE-SHOT timers can be in the COMPLETED state */ + *p_err = OS_ERR_NONE; + remain = 0u; + break; + + case OS_TMR_STATE_UNUSED: + *p_err = OS_ERR_TMR_INACTIVE; + remain = 0u; + break; + + default: + *p_err = OS_ERR_TMR_INVALID_STATE; + remain = 0u; + break; + } + + OS_TmrUnlock(); + + return (remain); +} + + +/* +************************************************************************************************************************ +* SET A TIMER +* +* Description: This function is called by your application code to set a timer. +* +* Arguments : p_tmr Is a pointer to a timer control block +* +* dly Initial delay. +* If the timer is configured for ONE-SHOT mode, this is the timeout used +* If the timer is configured for PERIODIC mode, this is the first timeout to wait for +* before the timer starts entering periodic mode +* +* period The 'period' being repeated for the timer. +* If you specified 'OS_OPT_TMR_PERIODIC' as an option, when the timer expires, it will +* automatically restart with the same period. +* +* p_callback Is a pointer to a callback function that will be called when the timer expires. The +* callback function must be declared as follows: +* +* void MyCallback (OS_TMR *p_tmr, void *p_arg); +* +* p_callback_arg Is an argument (a pointer) that is passed to the callback function when it is called. +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The timer was configured as expected +* OS_ERR_OBJ_TYPE If the object type is invalid +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer or invalid option +* OS_ERR_TMR_INVALID_CALLBACK you specified an invalid callback for a periodic timer +* OS_ERR_TMR_INVALID_DLY You specified an invalid delay +* OS_ERR_TMR_INVALID_PERIOD You specified an invalid period +* OS_ERR_TMR_ISR If the call was made from an ISR +* +* Returns : none +* +* Note(s) : 1) This function can be called on a running timer. The change to the delay and period will only +* take effect after the current period or delay has passed. Change to the callback will take +* effect immediately. +************************************************************************************************************************ +*/ + +void OSTmrSet (OS_TMR *p_tmr, + OS_TICK dly, + OS_TICK period, + OS_TMR_CALLBACK_PTR p_callback, + void *p_callback_arg, + OS_ERR *p_err) +{ +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return; + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return; + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { /* Validate 'p_tmr' */ + *p_err = OS_ERR_TMR_INVALID; + return; + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return; + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + switch (p_tmr->Opt) { + case OS_OPT_TMR_PERIODIC: + if (period == 0u) { + *p_err = OS_ERR_TMR_INVALID_PERIOD; + return; + } + + if (p_callback == (OS_TMR_CALLBACK_PTR)0) { /* No point in a periodic timer without a callback */ + *p_err = OS_ERR_TMR_INVALID_CALLBACK; + return; + } + break; + + case OS_OPT_TMR_ONE_SHOT: + if (dly == 0u) { + *p_err = OS_ERR_TMR_INVALID_DLY; + return; + } + break; + + default: + *p_err = OS_ERR_TMR_INVALID; + return; + } +#endif + + OS_TmrLock(); + + p_tmr->Dly = dly * OSTmrToTicksMult; /* Convert Timer Delay to ticks */ + p_tmr->Period = period * OSTmrToTicksMult; /* Convert Timer Period to ticks */ + p_tmr->CallbackPtr = p_callback; + p_tmr->CallbackPtrArg = p_callback_arg; + + *p_err = OS_ERR_NONE; + + OS_TmrUnlock(); +} + + +/* +************************************************************************************************************************ +* START A TIMER +* +* Description: This function is called by your application code to start a timer. +* +* Arguments : p_tmr Is a pointer to an OS_TMR +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The timer was started +* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INACTIVE If the timer was not created +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer +* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state +* OS_ERR_TMR_ISR If the call was made from an ISR +* +* Returns : OS_TRUE is the timer was started +* OS_FALSE if not or upon an error +* +* Note(s) : 1) When starting/restarting a timer, regardless if it is in PERIODIC or ONE-SHOT mode, the timer is +* linked to the timer list with the OS_OPT_LINK_DLY option. This option sets the initial expiration +* time for the timer. For timers in PERIODIC mode, subsequent expiration times are handled by +* the OS_TmrTask(). +************************************************************************************************************************ +*/ + +CPU_BOOLEAN OSTmrStart (OS_TMR *p_tmr, + OS_ERR *p_err) +{ + CPU_BOOLEAN success; + OS_TICK time; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { + *p_err = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (OS_FALSE); + } +#endif + + OS_TmrLock(); + + CPU_CRITICAL_ENTER(); + if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */ + time = OSTmrTaskTickBase; + } else { +#if (OS_CFG_DYN_TICK_EN > 0u) + time = OSTickCtr + OS_DynTickGet(); +#else + time = OSTickCtr; +#endif + } + CPU_CRITICAL_EXIT(); + + + switch (p_tmr->State) { + case OS_TMR_STATE_RUNNING: /* Restart the timer */ + case OS_TMR_STATE_TIMEOUT: + p_tmr->State = OS_TMR_STATE_RUNNING; + OS_TmrUnlink(p_tmr, time); /* Remove from current position in List */ + if (p_tmr->Dly == 0u) { + p_tmr->Remain = p_tmr->Period; + } else { + p_tmr->Remain = p_tmr->Dly; + } + OS_TmrLink(p_tmr, time); /* Add timer to List */ + *p_err = OS_ERR_NONE; + success = OS_TRUE; + break; + + case OS_TMR_STATE_STOPPED: /* Start the timer */ + case OS_TMR_STATE_COMPLETED: + p_tmr->State = OS_TMR_STATE_RUNNING; + if (p_tmr->Dly == 0u) { + p_tmr->Remain = p_tmr->Period; + } else { + p_tmr->Remain = p_tmr->Dly; + } + OS_TmrLink(p_tmr, time); /* Add timer to List */ + *p_err = OS_ERR_NONE; + success = OS_TRUE; + break; + + case OS_TMR_STATE_UNUSED: /* Timer not created */ + *p_err = OS_ERR_TMR_INACTIVE; + success = OS_FALSE; + break; + + default: + *p_err = OS_ERR_TMR_INVALID_STATE; + success = OS_FALSE; + break; + } + + OS_TmrUnlock(); + + return (success); +} + + +/* +************************************************************************************************************************ +* FIND OUT WHAT STATE A TIMER IS IN +* +* Description: This function is called to determine what state the timer is in: +* +* OS_TMR_STATE_UNUSED the timer has not been created +* OS_TMR_STATE_STOPPED the timer has been created but has not been started or has been stopped +* OS_TMR_STATE_COMPLETED the timer is in ONE-SHOT mode and has completed it's timeout +* OS_TMR_SATE_RUNNING the timer is currently running +* +* Arguments : p_tmr Is a pointer to the desired timer +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The return value reflects the state of the timer +* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer +* OS_ERR_TMR_INVALID_STATE If the timer is not in a valid state +* OS_ERR_TMR_ISR If the call was made from an ISR +* +* Returns : The current state of the timer (see description). +* +* Note(s) : none +************************************************************************************************************************ +*/ + +OS_STATE OSTmrStateGet (OS_TMR *p_tmr, + OS_ERR *p_err) +{ + OS_STATE state; + + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_TMR_STATE_UNUSED); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return (OS_TMR_STATE_UNUSED); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_TMR_STATE_UNUSED); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { + *p_err = OS_ERR_TMR_INVALID; + return (OS_TMR_STATE_UNUSED); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (OS_TMR_STATE_UNUSED); + } +#endif + + OS_TmrLock(); + + state = p_tmr->State; + switch (state) { + case OS_TMR_STATE_UNUSED: + case OS_TMR_STATE_STOPPED: + case OS_TMR_STATE_COMPLETED: + case OS_TMR_STATE_RUNNING: + case OS_TMR_STATE_TIMEOUT: + *p_err = OS_ERR_NONE; + break; + + default: + *p_err = OS_ERR_TMR_INVALID_STATE; + break; + } + + OS_TmrUnlock(); + + return (state); +} + + +/* +************************************************************************************************************************ +* STOP A TIMER +* +* Description: This function is called by your application code to stop a timer. +* +* Arguments : p_tmr Is a pointer to the timer to stop. +* +* opt Allows you to specify an option to this functions which can be: +* +* OS_OPT_TMR_NONE Do nothing special but stop the timer +* OS_OPT_TMR_CALLBACK Execute the callback function, pass it the callback argument +* specified when the timer was created. +* OS_OPT_TMR_CALLBACK_ARG Execute the callback function, pass it the callback argument +* specified in THIS function call +* +* callback_arg Is a pointer to a 'new' callback argument that can be passed to the callback function +* instead of the timer's callback argument. In other words, use 'callback_arg' passed in +* THIS function INSTEAD of p_tmr->OSTmrCallbackArg +* +* p_err Is a pointer to an error code. '*p_err' will contain one of the following: +* +* OS_ERR_NONE The timer has stopped +* OS_ERR_OBJ_TYPE If 'p_tmr' is not pointing to a timer +* OS_ERR_OPT_INVALID If you specified an invalid option for 'opt' +* OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet +* OS_ERR_TMR_INACTIVE If the timer was not created +* OS_ERR_TMR_INVALID If 'p_tmr' is a NULL pointer +* OS_ERR_TMR_INVALID_STATE The timer is in an invalid state +* OS_ERR_TMR_ISR If the function was called from an ISR +* OS_ERR_TMR_NO_CALLBACK If the timer does not have a callback function defined +* OS_ERR_TMR_STOPPED If the timer was already stopped +* +* Returns : OS_TRUE If we stopped the timer (if the timer is already stopped, we also return OS_TRUE) +* OS_FALSE If not +* +* Note(s) : none +************************************************************************************************************************ +*/ + +CPU_BOOLEAN OSTmrStop (OS_TMR *p_tmr, + OS_OPT opt, + void *p_callback_arg, + OS_ERR *p_err) +{ + OS_TMR_CALLBACK_PTR p_fnct; + CPU_BOOLEAN success; + OS_TICK time; + CPU_SR_ALLOC(); + + +#ifdef OS_SAFETY_CRITICAL + if (p_err == (OS_ERR *)0) { + OS_SAFETY_CRITICAL_EXCEPTION(); + return (OS_FALSE); + } +#endif + +#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) + if (OSIntNestingCtr > 0u) { /* See if trying to call from an ISR */ + *p_err = OS_ERR_TMR_ISR; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u) + if (OSRunning != OS_STATE_OS_RUNNING) { /* Is the kernel running? */ + *p_err = OS_ERR_OS_NOT_RUNNING; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_ARG_CHK_EN > 0u) + if (p_tmr == (OS_TMR *)0) { + *p_err = OS_ERR_TMR_INVALID; + return (OS_FALSE); + } +#endif + +#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u) + if (p_tmr->Type != OS_OBJ_TYPE_TMR) { /* Make sure timer was created */ + *p_err = OS_ERR_OBJ_TYPE; + return (OS_FALSE); + } +#endif + + OS_TmrLock(); + + CPU_CRITICAL_ENTER(); + if (OSTCBCurPtr == &OSTmrTaskTCB) { /* Callbacks operate on the Tmr Task's tick base. */ + time = OSTmrTaskTickBase; + } else { +#if (OS_CFG_DYN_TICK_EN > 0u) + time = OSTickCtr + OS_DynTickGet(); +#else + time = OSTickCtr; +#endif + } + CPU_CRITICAL_EXIT(); + + switch (p_tmr->State) { + case OS_TMR_STATE_RUNNING: + case OS_TMR_STATE_TIMEOUT: + p_tmr->State = OS_TMR_STATE_STOPPED; /* Ensure that any callbacks see the stop state */ + switch (opt) { + case OS_OPT_TMR_CALLBACK: + OS_TmrUnlink(p_tmr, time); /* Remove from timer list */ + p_fnct = p_tmr->CallbackPtr; /* Execute callback function ... */ + if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { /* ... if available */ + (*p_fnct)(p_tmr, p_tmr->CallbackPtrArg);/* Use callback arg when timer was created */ + } else { + *p_err = OS_ERR_TMR_NO_CALLBACK; + } + break; + + case OS_OPT_TMR_CALLBACK_ARG: + OS_TmrUnlink(p_tmr, time); /* Remove from timer list */ + p_fnct = p_tmr->CallbackPtr; /* Execute callback function if available ... */ + if (p_fnct != (OS_TMR_CALLBACK_PTR)0) { + (*p_fnct)(p_tmr, p_callback_arg); /* .. using the 'callback_arg' provided in call */ + } else { + *p_err = OS_ERR_TMR_NO_CALLBACK; + } + break; + + case OS_OPT_TMR_NONE: + OS_TmrUnlink(p_tmr, time); /* Remove from timer list */ + break; + + default: + OS_TmrUnlock(); + *p_err = OS_ERR_OPT_INVALID; + return (OS_FALSE); + } + *p_err = OS_ERR_NONE; + success = OS_TRUE; + break; + + case OS_TMR_STATE_COMPLETED: /* Timer has already completed the ONE-SHOT or */ + case OS_TMR_STATE_STOPPED: /* ... timer has not started yet. */ + p_tmr->State = OS_TMR_STATE_STOPPED; + *p_err = OS_ERR_TMR_STOPPED; + success = OS_TRUE; + break; + + case OS_TMR_STATE_UNUSED: /* Timer was not created */ + *p_err = OS_ERR_TMR_INACTIVE; + success = OS_FALSE; + break; + + default: + *p_err = OS_ERR_TMR_INVALID_STATE; + success = OS_FALSE; + break; + } + + OS_TmrUnlock(); + + return (success); +} + + +/* +************************************************************************************************************************ +* CLEAR TIMER FIELDS +* +* Description: This function is called to clear all timer fields. +* +* Argument(s): p_tmr Is a pointer to the timer to clear +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TmrClr (OS_TMR *p_tmr) +{ + p_tmr->State = OS_TMR_STATE_UNUSED; /* Clear timer fields */ +#if (OS_OBJ_TYPE_REQ > 0u) + p_tmr->Type = OS_OBJ_TYPE_NONE; +#endif +#if (OS_CFG_DBG_EN > 0u) + p_tmr->NamePtr = (CPU_CHAR *)((void *)"?TMR"); +#endif + p_tmr->Dly = 0u; + p_tmr->Remain = 0u; + p_tmr->Period = 0u; + p_tmr->Opt = 0u; + p_tmr->CallbackPtr = (OS_TMR_CALLBACK_PTR)0; + p_tmr->CallbackPtrArg = (void *)0; + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr->PrevPtr = (OS_TMR *)0; +} + + +/* +************************************************************************************************************************ +* ADD/REMOVE TIMER TO/FROM DEBUG TABLE +* +* Description: These functions are called by uC/OS-III to add or remove a timer to/from a timer debug table. +* +* Arguments : p_tmr is a pointer to the timer to add/remove +* +* Returns : none +* +* Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it. +************************************************************************************************************************ +*/ + + +#if (OS_CFG_DBG_EN > 0u) +void OS_TmrDbgListAdd (OS_TMR *p_tmr) +{ + p_tmr->DbgPrevPtr = (OS_TMR *)0; + if (OSTmrDbgListPtr == (OS_TMR *)0) { + p_tmr->DbgNextPtr = (OS_TMR *)0; + } else { + p_tmr->DbgNextPtr = OSTmrDbgListPtr; + OSTmrDbgListPtr->DbgPrevPtr = p_tmr; + } + OSTmrDbgListPtr = p_tmr; +} + + + +void OS_TmrDbgListRemove (OS_TMR *p_tmr) +{ + OS_TMR *p_tmr_next; + OS_TMR *p_tmr_prev; + + + p_tmr_prev = p_tmr->DbgPrevPtr; + p_tmr_next = p_tmr->DbgNextPtr; + + if (p_tmr_prev == (OS_TMR *)0) { + OSTmrDbgListPtr = p_tmr_next; + if (p_tmr_next != (OS_TMR *)0) { + p_tmr_next->DbgPrevPtr = (OS_TMR *)0; + } + p_tmr->DbgNextPtr = (OS_TMR *)0; + + } else if (p_tmr_next == (OS_TMR *)0) { + p_tmr_prev->DbgNextPtr = (OS_TMR *)0; + p_tmr->DbgPrevPtr = (OS_TMR *)0; + + } else { + p_tmr_prev->DbgNextPtr = p_tmr_next; + p_tmr_next->DbgPrevPtr = p_tmr_prev; + p_tmr->DbgNextPtr = (OS_TMR *)0; + p_tmr->DbgPrevPtr = (OS_TMR *)0; + } +} +#endif + + +/* +************************************************************************************************************************ +* INITIALIZE THE TIMER MANAGER +* +* Description: This function is called by OSInit() to initialize the timer manager module. +* +* Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function. +* +* OS_ERR_NONE +* OS_ERR_TMR_STK_INVALID if you didn't specify a stack for the timer task +* OS_ERR_TMR_STK_SIZE_INVALID if you didn't allocate enough space for the timer stack +* OS_ERR_PRIO_INVALID if you specified the same priority as the idle task +* OS_ERR_xxx any error code returned by OSTaskCreate() +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TmrInit (OS_ERR *p_err) +{ +#if (OS_CFG_DBG_EN > 0u) + OSTmrQty = 0u; /* Keep track of the number of timers created */ + OSTmrDbgListPtr = (OS_TMR *)0; +#endif + + OSTmrListPtr = (OS_TMR *)0; /* Create an empty timer list */ +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries = 0u; +#endif + /* Calculate Timer to Ticks multiplier */ + OSTmrToTicksMult = OSCfg_TickRate_Hz / OSCfg_TmrTaskRate_Hz; + +#if (OS_CFG_TS_EN > 0u) + OSTmrTaskTime = 0u; + OSTmrTaskTimeMax = 0u; +#endif + + OSMutexCreate(&OSTmrMutex, /* Use a mutex to protect the timers */ +#if (OS_CFG_DBG_EN == 0u) + (CPU_CHAR *)0, +#else + (CPU_CHAR *)"OS Tmr Mutex", +#endif + p_err); + if (*p_err != OS_ERR_NONE) { + return; + } + + OS_TmrCondCreate(); + /* -------------- CREATE THE TIMER TASK --------------- */ + if (OSCfg_TmrTaskStkBasePtr == (CPU_STK *)0) { + *p_err = OS_ERR_TMR_STK_INVALID; + return; + } + + if (OSCfg_TmrTaskStkSize < OSCfg_StkSizeMin) { + *p_err = OS_ERR_TMR_STK_SIZE_INVALID; + return; + } + + if (OSCfg_TmrTaskPrio >= (OS_CFG_PRIO_MAX - 1u)) { + *p_err = OS_ERR_TMR_PRIO_INVALID; + return; + } + + OSTaskCreate(&OSTmrTaskTCB, +#if (OS_CFG_DBG_EN == 0u) + (CPU_CHAR *)0, +#else + (CPU_CHAR *)"uC/OS-III Timer Task", +#endif + OS_TmrTask, + (void *)0, + OSCfg_TmrTaskPrio, + OSCfg_TmrTaskStkBasePtr, + OSCfg_TmrTaskStkLimit, + OSCfg_TmrTaskStkSize, + 0u, + 0u, + (void *)0, + (OS_OPT_TASK_STK_CHK | (OS_OPT)(OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS)), + p_err); +} + + +/* +************************************************************************************************************************ +* ADD A TIMER TO THE TIMER LIST +* +* Description: This function is called to add a timer to the timer list. +* +* Arguments : p_tmr Is a pointer to the timer to add. +* +* time Is the system time when this timer was linked. +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TmrLink (OS_TMR *p_tmr, + OS_TICK time) +{ + OS_TMR *p_tmr1; + OS_TMR *p_tmr2; + OS_TICK remain; + OS_TICK delta; + + + if (OSTmrListPtr == (OS_TMR *)0) { /* Is the list empty? */ + p_tmr->NextPtr = (OS_TMR *)0; /* Yes, this is the first entry */ + p_tmr->PrevPtr = (OS_TMR *)0; + OSTmrListPtr = p_tmr; +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries = 1u; +#endif + OSTmrTaskTickBase = time; + OS_TmrCondSignal(); + + return; + } + +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries++; +#endif + + delta = (time + p_tmr->Remain) - OSTmrTaskTickBase; + + p_tmr2 = OSTmrListPtr; /* No, Insert somewhere in the list in delta order */ + remain = p_tmr2->Remain; + + if ((delta < remain) && + (p_tmr2->PrevPtr == (OS_TMR *)0)) { /* Are we the new head of the list? */ + p_tmr2->Remain = remain - delta; + p_tmr->PrevPtr = (OS_TMR *)0; + p_tmr->NextPtr = p_tmr2; + p_tmr2->PrevPtr = p_tmr; + OSTmrListPtr = p_tmr; + + OSTmrTaskTickBase = time; + OS_TmrCondSignal(); + + return; + } + + /* No */ + delta -= remain; /* Make delta relative to the current head. */ + p_tmr1 = p_tmr2; + p_tmr2 = p_tmr1->NextPtr; + + + while ((p_tmr2 != (OS_TMR *)0) && /* Find the appropriate position in the delta list. */ + (delta >= p_tmr2->Remain)) { + delta -= p_tmr2->Remain; /* Update our delta as we traverse the list. */ + p_tmr1 = p_tmr2; + p_tmr2 = p_tmr2->NextPtr; + } + + + if (p_tmr2 != (OS_TMR *)0) { /* Our entry is not the last element in the list. */ + p_tmr1 = p_tmr2->PrevPtr; + p_tmr->Remain = delta; /* Store remaining time */ + p_tmr->PrevPtr = p_tmr1; + p_tmr->NextPtr = p_tmr2; + p_tmr2->Remain -= delta; /* Reduce time of next entry in the list */ + p_tmr2->PrevPtr = p_tmr; + p_tmr1->NextPtr = p_tmr; + + } else { /* Our entry belongs at the end of the list. */ + p_tmr->Remain = delta; + p_tmr->PrevPtr = p_tmr1; + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr1->NextPtr = p_tmr; + } +} + + +/* +************************************************************************************************************************ +* REMOVE A TIMER FROM THE TIMER LIST +* +* Description: This function is called to remove the timer from the timer list. +* +* Arguments : p_tmr Is a pointer to the timer to remove. +* +* time Is the system time when this timer was unlinked. +* ----- +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +void OS_TmrUnlink (OS_TMR *p_tmr, + OS_TICK time) +{ + OS_TMR *p_tmr1; + OS_TMR *p_tmr2; + OS_TICK elapsed; + + + p_tmr1 = p_tmr->PrevPtr; + p_tmr2 = p_tmr->NextPtr; + if (p_tmr1 == (OS_TMR *)0) { + if (p_tmr2 == (OS_TMR *)0) { /* Remove the ONLY entry in the list? */ + OSTmrListPtr = (OS_TMR *)0; +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries = 0u; +#endif + p_tmr->Remain = 0u; + + OSTmrTaskTickBase = time; + OS_TmrCondSignal(); + } else { +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries--; +#endif + elapsed = time - OSTmrTaskTickBase; + p_tmr2->PrevPtr = (OS_TMR *)0; + p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta */ + OSTmrListPtr = p_tmr2; + + while ((elapsed > 0u) && + (p_tmr2 != (OS_TMR *)0)) { + + if (elapsed > p_tmr2->Remain) { + elapsed -= p_tmr2->Remain; + p_tmr2->Remain = 0u; + } else { + p_tmr2->Remain -= elapsed; + elapsed = 0u; + } + + + p_tmr1 = p_tmr2; + p_tmr2 = p_tmr1->NextPtr; + } + + if ((OSTmrListPtr->Remain != p_tmr->Remain) || /* Reload if new head has a different delay ... */ + (OSTmrListPtr->Remain == 0u)) { /* ... or has already timed out. */ + OSTmrTaskTickBase = time; + OS_TmrCondSignal(); + } + + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr->Remain = 0u; + } + } else { +#if (OS_CFG_DBG_EN > 0u) + OSTmrListEntries--; +#endif + p_tmr1->NextPtr = p_tmr2; + if (p_tmr2 != (OS_TMR *)0) { + p_tmr2->PrevPtr = p_tmr1; + p_tmr2->Remain += p_tmr->Remain; /* Add back the ticks to the delta list */ + } + p_tmr->PrevPtr = (OS_TMR *)0; + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr->Remain = 0u; + } +} + + +/* +************************************************************************************************************************ +* TIMER MANAGEMENT TASK +* +* Description: This task is created by OS_TmrInit(). +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +* +* 2) The timer list is processed in two stages. +* a) Subtract the expired time from the delta list, which leaves expired timers at the head. +* b) Process each of the expired timers by invoking its callback (if any) and removing it. +* This method allows timer callbacks to Link/Unlink timers while maintaining the correct delta values. +* +* 3) Timer callbacks are allowed to make calls to the Timer APIs. +************************************************************************************************************************ +*/ + +void OS_TmrTask (void *p_arg) +{ + OS_TMR_CALLBACK_PTR p_fnct; + OS_TMR *p_tmr; + OS_TICK timeout; + OS_TICK elapsed; + OS_TICK time; +#if (OS_CFG_TS_EN > 0u) + CPU_TS ts_start; +#endif + CPU_SR_ALLOC(); + + + (void)p_arg; /* Not using 'p_arg', prevent compiler warning */ + + OS_TmrLock(); + + for (;;) { + if (OSTmrListPtr == (OS_TMR *)0) { + timeout = 0u; + } else { + timeout = OSTmrListPtr->Remain; + } + + OS_TmrCondWait(timeout); /* Suspend the timer task until it needs to process ... */ + /* ... the timer list again. Also release the mutex ... */ + /* ... so that application tasks can add/remove timers. */ + + if (OSTmrListPtr == (OS_TMR *)0) { /* Suppresses static analyzer warnings. */ + continue; + } + +#if (OS_CFG_TS_EN > 0u) + ts_start = OS_TS_GET(); +#endif + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_DYN_TICK_EN > 0u) + time = OSTickCtr + OS_DynTickGet(); +#else + time = OSTickCtr; +#endif + CPU_CRITICAL_EXIT(); + elapsed = time - OSTmrTaskTickBase; + OSTmrTaskTickBase = time; + + /* Update the delta values. */ + p_tmr = OSTmrListPtr; + while ((elapsed != 0u) && + (p_tmr != (OS_TMR *)0)) { + + if (elapsed > p_tmr->Remain) { + elapsed -= p_tmr->Remain; + p_tmr->Remain = 0u; + } else { + p_tmr->Remain -= elapsed; + elapsed = 0u; + } + + p_tmr = p_tmr->NextPtr; + } + + /* Process timers that have expired. */ + p_tmr = OSTmrListPtr; + + while ((p_tmr != (OS_TMR *)0) && + (p_tmr->Remain == 0u)) { + p_tmr->State = OS_TMR_STATE_TIMEOUT; + /* Execute callback function if available */ + p_fnct = p_tmr->CallbackPtr; + if (p_fnct != (OS_TMR_CALLBACK_PTR)0u) { + (*p_fnct)(p_tmr, p_tmr->CallbackPtrArg); + } + + if (p_tmr->State == OS_TMR_STATE_TIMEOUT) { + OS_TmrUnlink(p_tmr, OSTmrTaskTickBase); + + if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) { + p_tmr->State = OS_TMR_STATE_RUNNING; + p_tmr->Remain = p_tmr->Period; + OS_TmrLink(p_tmr, OSTmrTaskTickBase); + } else { + p_tmr->PrevPtr = (OS_TMR *)0; + p_tmr->NextPtr = (OS_TMR *)0; + p_tmr->Remain = 0u; + p_tmr->State = OS_TMR_STATE_COMPLETED; + } + } + + p_tmr = OSTmrListPtr; + } + +#if (OS_CFG_TS_EN > 0u) + OSTmrTaskTime = OS_TS_GET() - ts_start; /* Measure execution time of timer task */ + if (OSTmrTaskTimeMax < OSTmrTaskTime) { + OSTmrTaskTimeMax = OSTmrTaskTime; + } +#endif + } +} + + +/* +************************************************************************************************************************ +* TIMER MANAGEMENT LOCKING MECHANISM +* +* Description: These functions are used to handle timer critical sections. The method uses a mutex +* to protect access to the global timer list. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) These functions are INTERNAL to uC/OS-III and your application MUST NOT call them. +************************************************************************************************************************ +*/ + +static void OS_TmrLock (void) +{ + OS_ERR err; + + + OSMutexPend(&OSTmrMutex, 0u, OS_OPT_PEND_BLOCKING, (CPU_TS *)0, &err); +} + + +static void OS_TmrUnlock (void) +{ + OS_ERR err; + + + OSMutexPost(&OSTmrMutex, OS_OPT_POST_NONE, &err); +} + + +/* +************************************************************************************************************************ +* CREATE TIMER TASK CONDITION VARIABLE +* +* Description: Initializes a condition variable for INTERNAL use ONLY. +* +* Arguments : none +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +static void OS_TmrCondCreate (void) +{ + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); +#if (OS_OBJ_TYPE_REQ > 0u) + OSTmrCond.Type = OS_OBJ_TYPE_COND; /* Mark the data structure as a condition variable. */ +#endif + OSTmrCond.Mutex = &OSTmrMutex; /* Bind the timer mutex to the condition variable. */ + OS_PendListInit(&OSTmrCond.PendList); /* Initialize the waiting list */ + CPU_CRITICAL_EXIT(); +} + + +/* +************************************************************************************************************************ +* WAIT ON TIMER TASK CONDITION VARIABLE +* +* Description: Allows the timer task to release the global mutex and pend atomically. This ensures that +* timers are only added/removed after the timer task has processed the current list and pended +* for the next timeout. The timer task will always acquire the mutex before returning from this function. +* +* Arguments : timeout The number of ticks before the timer task will wake up. +* A value of zero signifies an indefinite pend. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +static void OS_TmrCondWait (OS_TICK timeout) +{ + OS_TCB *p_tcb; + OS_PEND_LIST *p_pend_list; + CPU_TS ts; + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ + OSTmrMutex.TS = ts; +#else + ts = 0u; +#endif + /* Release mutex to other tasks. */ + OS_MutexGrpRemove(&OSTmrTaskTCB, &OSTmrMutex); + p_pend_list = &OSTmrMutex.PendList; + + if (OSTmrTaskTCB.Prio != OSTmrTaskTCB.BasePrio) { /* Restore our original prio. */ + OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(&OSTmrTaskTCB, OSTmrTaskTCB.Prio); + OSTmrTaskTCB.Prio = OSTmrTaskTCB.BasePrio; + OSPrioCur = OSTmrTaskTCB.BasePrio; + } + + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Any task waiting on mutex? */ + OSTmrMutex.OwnerTCBPtr = (OS_TCB *)0; /* No */ + OSTmrMutex.OwnerNestingCtr = 0u; + } else { + p_tcb = p_pend_list->HeadPtr; /* Yes, give mutex to new owner */ + OSTmrMutex.OwnerTCBPtr = p_tcb; + OSTmrMutex.OwnerNestingCtr = 1u; + OS_MutexGrpAdd(p_tcb, &OSTmrMutex); + /* Post to mutex */ + OS_Post((OS_PEND_OBJ *)((void *)&OSTmrMutex), + p_tcb, + (void *) 0, + 0u, + ts); + } + + OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrCond), /* Pend on the condition variable. */ + &OSTmrTaskTCB, + OS_TASK_PEND_ON_COND, + timeout); + CPU_CRITICAL_EXIT(); + + OSSched(); + + CPU_CRITICAL_ENTER(); /* Either we timed out, or were signaled. */ + + if (OSTmrMutex.OwnerTCBPtr == (OS_TCB *)0) { /* Can we grab the mutex? */ + OS_MutexGrpAdd(&OSTmrTaskTCB, &OSTmrMutex); /* Yes, no-one else pending. */ + OSTmrMutex.OwnerTCBPtr = &OSTmrTaskTCB; + OSTmrMutex.OwnerNestingCtr = 1u; + CPU_CRITICAL_EXIT(); + } else { + p_tcb = OSTmrMutex.OwnerTCBPtr; /* No, we need to wait for it. */ + if (p_tcb->Prio > OSTmrTaskTCB.Prio) { /* See if mutex owner has a lower priority than TmrTask.*/ + OS_TaskChangePrio(p_tcb, OSTmrTaskTCB.Prio); + } + + OS_Pend((OS_PEND_OBJ *)((void *)&OSTmrMutex), /* Block TmrTask until it gets the Mutex. */ + &OSTmrTaskTCB, + OS_TASK_PEND_ON_MUTEX, + 0u); + CPU_CRITICAL_EXIT(); + + OSSched(); + } +} + + +/* +************************************************************************************************************************ +* SIGNAL THE TIMER TASK CONDITION VARIABLE +* +* Description: Used to signal the timer task when a timer is added/removed which requires the task to reload +* its timeout. We ensure that this function is always called with the timer mutex locked. +* +* Arguments : none. +* +* Returns : none +* +* Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it. +************************************************************************************************************************ +*/ + +static void OS_TmrCondSignal (void) +{ + OS_PEND_LIST *p_pend_list; + CPU_TS ts; + CPU_SR_ALLOC(); + + + CPU_CRITICAL_ENTER(); +#if (OS_CFG_TS_EN > 0u) + ts = OS_TS_GET(); /* Get timestamp */ + OSTmrMutex.TS = ts; +#else + ts = 0u; +#endif + + p_pend_list = &OSTmrCond.PendList; + + if (p_pend_list->HeadPtr == (OS_TCB *)0) { /* Timer task waiting on cond? */ + CPU_CRITICAL_EXIT(); + return; /* No, nothing to signal. */ + } else { + /* Yes, signal the timer task. */ + OS_Post((OS_PEND_OBJ *)((void *)&OSTmrCond), + &OSTmrTaskTCB, + (void *) 0, + 0u, + ts); + } + + CPU_CRITICAL_EXIT(); +} +#endif diff --git a/rtos/uC-OS3/Source/os_trace.h b/rtos/uC-OS3/Source/os_trace.h new file mode 100644 index 00000000..6def1d63 --- /dev/null +++ b/rtos/uC-OS3/Source/os_trace.h @@ -0,0 +1,476 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* File : os_trace.h +* Version : V3.08.00 +********************************************************************************************************* +* Note(s) : (1) The header file os_trace_events.h is the interface between uC/OS-III and your +* trace recorder of choice. To support trace recording, include one of the sub-folders +* at uCOS-III/Trace/ into your project. +********************************************************************************************************* +*/ + +#ifndef OS_TRACE_H +#define OS_TRACE_H + + +#include + +#if (defined(OS_CFG_TRACE_EN) && (OS_CFG_TRACE_EN > 0u)) +#include /* See Note #1. */ +#endif + + +/* +************************************************************************************************************************** +* uC/OS-III Trace Default Macros (Empty) +************************************************************************************************************************** +*/ + +#ifndef OS_TRACE_INIT +#define OS_TRACE_INIT() +#endif +#ifndef OS_TRACE_START +#define OS_TRACE_START() +#endif +#ifndef OS_TRACE_STOP +#define OS_TRACE_STOP() +#endif +#ifndef OS_TRACE_CLEAR +#define OS_TRACE_CLEAR() +#endif + +#ifndef OS_TRACE_ISR_ENTER +#define OS_TRACE_ISR_ENTER() +#endif +#ifndef OS_TRACE_ISR_EXIT +#define OS_TRACE_ISR_EXIT() +#endif +#ifndef OS_TRACE_ISR_EXIT_TO_SCHEDULER +#define OS_TRACE_ISR_EXIT_TO_SCHEDULER() +#endif + +#ifndef OS_TRACE_TICK_INCREMENT +#define OS_TRACE_TICK_INCREMENT(OSTickCtr) +#endif + +#ifndef OS_TRACE_TASK_CREATE +#define OS_TRACE_TASK_CREATE(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_CREATE_FAILED +#define OS_TRACE_TASK_CREATE_FAILED(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_DEL +#define OS_TRACE_TASK_DEL(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_READY +#define OS_TRACE_TASK_READY(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SWITCHED_IN +#define OS_TRACE_TASK_SWITCHED_IN(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_DLY +#define OS_TRACE_TASK_DLY(dly_ticks) +#endif + +#ifndef OS_TRACE_TASK_SUSPEND +#define OS_TRACE_TASK_SUSPEND(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SUSPENDED +#define OS_TRACE_TASK_SUSPENDED(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_RESUME +#define OS_TRACE_TASK_RESUME(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_PREEMPT +#define OS_TRACE_TASK_PREEMPT(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_PRIO_CHANGE +#define OS_TRACE_TASK_PRIO_CHANGE(p_tcb, prio) +#endif + +#ifndef OS_TRACE_ISR_REGISTER +#define OS_TRACE_ISR_REGISTER(isr_id, isr_name, isr_prio) +#endif + +#ifndef OS_TRACE_ISR_BEGIN +#define OS_TRACE_ISR_BEGIN(isr_id) +#endif + +#ifndef OS_TRACE_ISR_END +#define OS_TRACE_ISR_END() +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_CREATE +#define OS_TRACE_TASK_MSG_Q_CREATE(p_msg_q, p_name) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_POST +#define OS_TRACE_TASK_MSG_Q_POST(p_msg_q) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_POST_FAILED +#define OS_TRACE_TASK_MSG_Q_POST_FAILED(p_msg_q) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_PEND +#define OS_TRACE_TASK_MSG_Q_PEND(p_msg_q) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_PEND_FAILED +#define OS_TRACE_TASK_MSG_Q_PEND_FAILED(p_msg_q) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_PEND_BLOCK +#define OS_TRACE_TASK_MSG_Q_PEND_BLOCK(p_msg_q) +#endif + +#ifndef OS_TRACE_TASK_SEM_CREATE +#define OS_TRACE_TASK_SEM_CREATE(p_tcb, p_name) +#endif + +#ifndef OS_TRACE_TASK_SEM_POST +#define OS_TRACE_TASK_SEM_POST(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SEM_POST_FAILED +#define OS_TRACE_TASK_SEM_POST_FAILED(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SEM_PEND +#define OS_TRACE_TASK_SEM_PEND(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SEM_PEND_FAILED +#define OS_TRACE_TASK_SEM_PEND_FAILED(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SEM_PEND_BLOCK +#define OS_TRACE_TASK_SEM_PEND_BLOCK(p_tcb) +#endif + +#ifndef OS_TRACE_MUTEX_CREATE +#define OS_TRACE_MUTEX_CREATE(p_mutex, p_name) +#endif + +#ifndef OS_TRACE_MUTEX_DEL +#define OS_TRACE_MUTEX_DEL(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_POST +#define OS_TRACE_MUTEX_POST(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_POST_FAILED +#define OS_TRACE_MUTEX_POST_FAILED(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_PEND +#define OS_TRACE_MUTEX_PEND(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_PEND_FAILED +#define OS_TRACE_MUTEX_PEND_FAILED(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_PEND_BLOCK +#define OS_TRACE_MUTEX_PEND_BLOCK(p_mutex) +#endif + +#ifndef OS_TRACE_MUTEX_TASK_PRIO_INHERIT +#define OS_TRACE_MUTEX_TASK_PRIO_INHERIT(p_tcb, prio) +#endif + +#ifndef OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT +#define OS_TRACE_MUTEX_TASK_PRIO_DISINHERIT(p_tcb, prio) +#endif + +#ifndef OS_TRACE_SEM_CREATE +#define OS_TRACE_SEM_CREATE(p_sem, p_name) +#endif + +#ifndef OS_TRACE_SEM_DEL +#define OS_TRACE_SEM_DEL(p_sem) +#endif + +#ifndef OS_TRACE_SEM_POST +#define OS_TRACE_SEM_POST(p_sem) +#endif + +#ifndef OS_TRACE_SEM_POST_FAILED +#define OS_TRACE_SEM_POST_FAILED(p_sem) +#endif + +#ifndef OS_TRACE_SEM_PEND +#define OS_TRACE_SEM_PEND(p_sem) +#endif + +#ifndef OS_TRACE_SEM_PEND_FAILED +#define OS_TRACE_SEM_PEND_FAILED(p_sem) +#endif + +#ifndef OS_TRACE_SEM_PEND_BLOCK +#define OS_TRACE_SEM_PEND_BLOCK(p_sem) +#endif + +#ifndef OS_TRACE_Q_CREATE +#define OS_TRACE_Q_CREATE(p_q, p_name) +#endif + +#ifndef OS_TRACE_Q_DEL +#define OS_TRACE_Q_DEL(p_q) +#endif + +#ifndef OS_TRACE_Q_POST +#define OS_TRACE_Q_POST(p_q) +#endif + +#ifndef OS_TRACE_Q_POST_FAILED +#define OS_TRACE_Q_POST_FAILED(p_q) +#endif + +#ifndef OS_TRACE_Q_PEND +#define OS_TRACE_Q_PEND(p_q) +#endif + +#ifndef OS_TRACE_Q_PEND_FAILED +#define OS_TRACE_Q_PEND_FAILED(p_q) +#endif + +#ifndef OS_TRACE_Q_PEND_BLOCK +#define OS_TRACE_Q_PEND_BLOCK(p_q) +#endif + +#ifndef OS_TRACE_FLAG_CREATE +#define OS_TRACE_FLAG_CREATE(p_grp, p_name) +#endif + +#ifndef OS_TRACE_FLAG_DEL +#define OS_TRACE_FLAG_DEL(p_grp) +#endif + +#ifndef OS_TRACE_FLAG_POST +#define OS_TRACE_FLAG_POST(p_grp) +#endif + +#ifndef OS_TRACE_FLAG_POST_FAILED +#define OS_TRACE_FLAG_POST_FAILED(p_grp) +#endif + +#ifndef OS_TRACE_FLAG_PEND +#define OS_TRACE_FLAG_PEND(p_grp) +#endif + +#ifndef OS_TRACE_FLAG_PEND_FAILED +#define OS_TRACE_FLAG_PEND_FAILED(p_grp) +#endif + +#ifndef OS_TRACE_FLAG_PEND_BLOCK +#define OS_TRACE_FLAG_PEND_BLOCK(p_grp) +#endif + +#ifndef OS_TRACE_MEM_CREATE +#define OS_TRACE_MEM_CREATE(p_mem, p_name) +#endif + +#ifndef OS_TRACE_MEM_PUT +#define OS_TRACE_MEM_PUT(p_mem) +#endif + +#ifndef OS_TRACE_MEM_PUT_FAILED +#define OS_TRACE_MEM_PUT_FAILED(p_mem) +#endif + +#ifndef OS_TRACE_MEM_GET +#define OS_TRACE_MEM_GET(p_mem) +#endif + +#ifndef OS_TRACE_MEM_GET_FAILED +#define OS_TRACE_MEM_GET_FAILED(p_mem) +#endif + +#ifndef OS_TRACE_MUTEX_DEL_ENTER +#define OS_TRACE_MUTEX_DEL_ENTER(p_mutex, opt) +#endif + +#ifndef OS_TRACE_MUTEX_POST_ENTER +#define OS_TRACE_MUTEX_POST_ENTER(p_mutex, opt) +#endif + +#ifndef OS_TRACE_MUTEX_PEND_ENTER +#define OS_TRACE_MUTEX_PEND_ENTER(p_mutex, timeout, opt, p_ts) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_POST_ENTER +#define OS_TRACE_TASK_MSG_Q_POST_ENTER(p_msg_q, p_void, msg_size, opt) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_PEND_ENTER +#define OS_TRACE_TASK_MSG_Q_PEND_ENTER(p_msg_q, timeout, opt, p_msg_size, p_ts) +#endif + +#ifndef OS_TRACE_TASK_SEM_POST_ENTER +#define OS_TRACE_TASK_SEM_POST_ENTER(p_tcb, opt) +#endif + +#ifndef OS_TRACE_TASK_SEM_PEND_ENTER +#define OS_TRACE_TASK_SEM_PEND_ENTER(p_tcb, timeout, opt, p_ts) +#endif + +#ifndef OS_TRACE_TASK_RESUME_ENTER +#define OS_TRACE_TASK_RESUME_ENTER(p_tcb) +#endif + +#ifndef OS_TRACE_TASK_SUSPEND_ENTER +#define OS_TRACE_TASK_SUSPEND_ENTER(p_tcb) +#endif + +#ifndef OS_TRACE_SEM_DEL_ENTER +#define OS_TRACE_SEM_DEL_ENTER(p_sem, opt) +#endif + +#ifndef OS_TRACE_SEM_POST_ENTER +#define OS_TRACE_SEM_POST_ENTER(p_sem, opt) +#endif + +#ifndef OS_TRACE_SEM_PEND_ENTER +#define OS_TRACE_SEM_PEND_ENTER(p_sem, timeout, opt, p_ts) +#endif + +#ifndef OS_TRACE_Q_DEL_ENTER +#define OS_TRACE_Q_DEL_ENTER(p_q, opt) +#endif + +#ifndef OS_TRACE_Q_POST_ENTER +#define OS_TRACE_Q_POST_ENTER(p_q, p_void, msg_size, opt) +#endif + +#ifndef OS_TRACE_Q_PEND_ENTER +#define OS_TRACE_Q_PEND_ENTER(p_q, timeout, opt, p_msg_size, p_ts) +#endif + +#ifndef OS_TRACE_FLAG_DEL_ENTER +#define OS_TRACE_FLAG_DEL_ENTER(p_grp, opt) +#endif + +#ifndef OS_TRACE_FLAG_POST_ENTER +#define OS_TRACE_FLAG_POST_ENTER(p_grp, flags, opt) +#endif + +#ifndef OS_TRACE_FLAG_PEND_ENTER +#define OS_TRACE_FLAG_PEND_ENTER(p_grp, flags, timeout, opt, p_ts) +#endif + +#ifndef OS_TRACE_MEM_PUT_ENTER +#define OS_TRACE_MEM_PUT_ENTER(p_mem, p_blk) +#endif + +#ifndef OS_TRACE_MEM_GET_ENTER +#define OS_TRACE_MEM_GET_ENTER(p_mem) +#endif + +#ifndef OS_TRACE_MUTEX_DEL_EXIT +#define OS_TRACE_MUTEX_DEL_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_MUTEX_POST_EXIT +#define OS_TRACE_MUTEX_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_MUTEX_PEND_EXIT +#define OS_TRACE_MUTEX_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_POST_EXIT +#define OS_TRACE_TASK_MSG_Q_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_MSG_Q_PEND_EXIT +#define OS_TRACE_TASK_MSG_Q_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_SEM_POST_EXIT +#define OS_TRACE_TASK_SEM_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_SEM_PEND_EXIT +#define OS_TRACE_TASK_SEM_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_RESUME_EXIT +#define OS_TRACE_TASK_RESUME_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_TASK_SUSPEND_EXIT +#define OS_TRACE_TASK_SUSPEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_SEM_DEL_EXIT +#define OS_TRACE_SEM_DEL_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_SEM_POST_EXIT +#define OS_TRACE_SEM_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_SEM_PEND_EXIT +#define OS_TRACE_SEM_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_Q_DEL_EXIT +#define OS_TRACE_Q_DEL_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_Q_POST_EXIT +#define OS_TRACE_Q_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_Q_PEND_EXIT +#define OS_TRACE_Q_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_FLAG_DEL_EXIT +#define OS_TRACE_FLAG_DEL_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_FLAG_POST_EXIT +#define OS_TRACE_FLAG_POST_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_FLAG_PEND_EXIT +#define OS_TRACE_FLAG_PEND_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_MEM_PUT_EXIT +#define OS_TRACE_MEM_PUT_EXIT(RetVal) +#endif + +#ifndef OS_TRACE_MEM_GET_EXIT +#define OS_TRACE_MEM_GET_EXIT(RetVal) +#endif + +#endif diff --git a/rtos/uC-OS3/Source/os_type.h b/rtos/uC-OS3/Source/os_type.h new file mode 100644 index 00000000..d33a90a6 --- /dev/null +++ b/rtos/uC-OS3/Source/os_type.h @@ -0,0 +1,87 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* File : os_type.h +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#ifndef OS_TYPE_H +#define OS_TYPE_H + +#ifdef VSC_INCLUDE_H_FILE_NAMES +const CPU_CHAR *os_type__h = "$Id: $"; +#endif + +/* +************************************************************************************************************************ +* INCLUDE HEADER FILES +************************************************************************************************************************ +*/ + + /* Description # Bits */ + /* */ + /* ----------------------------------------------------------- */ + +typedef CPU_INT16U OS_CPU_USAGE; /* CPU Usage 0..10000 <16>/32 */ + +typedef CPU_INT32U OS_CTR; /* Counter, 32 */ + +typedef CPU_INT32U OS_CTX_SW_CTR; /* Counter of context switches, 32 */ + +typedef CPU_INT32U OS_CYCLES; /* CPU clock cycles, <32>/64 */ + +typedef CPU_INT32U OS_FLAGS; /* Event flags, 8/16/<32> */ + +typedef CPU_INT32U OS_IDLE_CTR; /* Holds the number of times the idle task runs, <32>/64 */ + +typedef CPU_INT16U OS_MEM_QTY; /* Number of memory blocks, <16>/32 */ +typedef CPU_INT16U OS_MEM_SIZE; /* Size in bytes of a memory block, <16>/32 */ + +typedef CPU_INT16U OS_MSG_QTY; /* Number of OS_MSGs in the msg pool, <16>/32 */ +typedef CPU_INT16U OS_MSG_SIZE; /* Size of messages in number of bytes, <16>/32 */ + +typedef CPU_INT08U OS_NESTING_CTR; /* Interrupt and scheduler nesting, <8>/16/32 */ + +typedef CPU_INT16U OS_OBJ_QTY; /* Number of kernel objects counter, <16>/32 */ +typedef CPU_INT32U OS_OBJ_TYPE; /* Special flag to determine object type, 32 */ + +typedef CPU_INT16U OS_OPT; /* Holds function options, <16>/32 */ + +typedef CPU_INT08U OS_PRIO; /* Priority of a task, <8>/16/32 */ + +typedef CPU_INT16U OS_QTY; /* Quantity <16>/32 */ + +typedef CPU_INT32U OS_RATE_HZ; /* Rate in Hertz 32 */ + +#if (CPU_CFG_ADDR_SIZE == CPU_WORD_SIZE_64) /* Task register 8/16/<32/64> */ +typedef CPU_INT64U OS_REG; +#else +typedef CPU_INT32U OS_REG; +#endif +typedef CPU_INT08U OS_REG_ID; /* Index to task register <8>/16/32 */ + +typedef CPU_INT32U OS_SEM_CTR; /* Semaphore value 16/<32> */ + +typedef CPU_INT08U OS_STATE; /* State variable <8>/16/32 */ + +typedef CPU_INT08U OS_STATUS; /* Status <8>/16/32 */ + +typedef CPU_INT32U OS_TICK; /* Clock tick counter <32>/64 */ + +#endif diff --git a/rtos/uC-OS3/Source/os_var.c b/rtos/uC-OS3/Source/os_var.c new file mode 100644 index 00000000..15d6f883 --- /dev/null +++ b/rtos/uC-OS3/Source/os_var.c @@ -0,0 +1,33 @@ +/* +********************************************************************************************************* +* uC/OS-III +* The Real-Time Kernel +* +* Copyright 2009-2020 Silicon Laboratories Inc. www.silabs.com +* +* SPDX-License-Identifier: APACHE-2.0 +* +* This software is subject to an open source license and is distributed by +* Silicon Laboratories Inc. pursuant to the terms of the Apache License, +* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. +* +********************************************************************************************************* +*/ + +/* +********************************************************************************************************* +* VARIABLES +* +* File : os_var.c +* Version : V3.08.00 +********************************************************************************************************* +*/ + +#define OS_GLOBALS + +#define MICRIUM_SOURCE +#include "os.h" + +#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES +const CPU_CHAR *os_var__c = "$Id: $"; +#endif diff --git a/rtos/uC-OS3/readme.md b/rtos/uC-OS3/readme.md new file mode 100644 index 00000000..5772fddb --- /dev/null +++ b/rtos/uC-OS3/readme.md @@ -0,0 +1,7 @@ +# uC/OS-III + +µC/OS-III is a highly portable, ROMable, scalable, preemptive, real-time, deterministic, multitasking kernel for microprocessors, microcontrollers and DSPs. + +Offering unprecedented ease-of-use, μC/OS-III is delivered with complete 100% ANSI C source code and in-depth documentation. μC/OS-III runs on the largest number of processor architectures, with ports available for download from the Micrium Web site. + +## For the complete documentation, visit https://doc.micrium.com/display/ucos/ \ No newline at end of file