mirror of
https://github.com/jie65535/stm32f10x-uC-OS-II.git
synced 2024-07-27 19:10:55 +08:00
upload template
This commit is contained in:
10
uCOS-II Template/uCOS-II/Config/app_cfg.c
Normal file
10
uCOS-II Template/uCOS-II/Config/app_cfg.c
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "stm32f10x.h"
|
||||
#include "os_cfg.h"
|
||||
|
||||
// ϵͳʱ<CDB3><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
void OSTick_Init(void)
|
||||
{
|
||||
RCC_ClocksTypeDef RCC_ClocksStructure;
|
||||
RCC_GetClocksFreq(&RCC_ClocksStructure);
|
||||
SysTick_Config(RCC_ClocksStructure.HCLK_Frequency / OS_TICKS_PER_SEC );
|
||||
}
|
6
uCOS-II Template/uCOS-II/Config/app_cfg.h
Normal file
6
uCOS-II Template/uCOS-II/Config/app_cfg.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __APP_CFG_H__
|
||||
#define __APP_CFG_H__
|
||||
|
||||
void OSTick_Init(void);
|
||||
|
||||
#endif
|
8
uCOS-II Template/uCOS-II/Config/includes.h
Normal file
8
uCOS-II Template/uCOS-II/Config/includes.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _INCLUDES_H_
|
||||
#define _INCLUDES_H_
|
||||
|
||||
#include "os_cpu.h"
|
||||
#include "os_cfg.h"
|
||||
#include "ucos_ii.h"
|
||||
|
||||
#endif
|
142
uCOS-II Template/uCOS-II/Config/os_cfg.h
Normal file
142
uCOS-II Template/uCOS-II/Config/os_cfg.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
*
|
||||
* (c) Copyright 1992-2007, Jean J. Labrosse, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* uC/OS-II Configuration File for V2.8x
|
||||
*
|
||||
* File : OS_CFG.H
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.85
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_CFG_H
|
||||
#define OS_CFG_H
|
||||
|
||||
/* ---------------------- MISCELLANEOUS ----------------------- */
|
||||
#define OS_APP_HOOKS_EN 0 /* Application-defined hooks are called from the uC/OS-II hooks */
|
||||
#define OS_ARG_CHK_EN 1 /* Enable (1) or Disable (0) argument checking */
|
||||
#define OS_CPU_HOOKS_EN 1 /* uC/OS-II hooks are found in the processor port files */
|
||||
|
||||
#define OS_DEBUG_EN 0 /* Enable(1) debug variables */
|
||||
#define OS_EVENT_MULTI_EN 1 /* Include code for OSEventPendMulti() */
|
||||
|
||||
#define OS_EVENT_NAME_SIZE 16 /* Determine the size of the name of a Sem, Mutex, Mbox or Q */
|
||||
|
||||
#define OS_LOWEST_PRIO 15 /* Defines the lowest priority that can be assigned ... */
|
||||
/* ... MUST NEVER be higher than 254! */
|
||||
|
||||
#define OS_MAX_EVENTS 10 /* Max. number of event control blocks in your application */
|
||||
#define OS_MAX_FLAGS 5 /* Max. number of Event Flag Groups in your application */
|
||||
#define OS_MAX_MEM_PART 5 /* Max. number of memory partitions */
|
||||
#define OS_MAX_QS 4 /* Max. number of queue control blocks in your application */
|
||||
#define OS_MAX_TASKS 8 /* Max. number of tasks in your application, MUST be >= 2 */
|
||||
|
||||
#define OS_SCHED_LOCK_EN 0 /* Include code for OSSchedLock() and OSSchedUnlock() */
|
||||
|
||||
#define OS_TICK_STEP_EN 1 /* Enable tick stepping feature for uC/OS-View */
|
||||
#define OS_TICKS_PER_SEC 1000 /* Set the number of ticks in one second */
|
||||
|
||||
|
||||
/* --------------------- TASK STACK SIZE ---------------------- */
|
||||
#define OS_TASK_TMR_STK_SIZE 128 /* Timer task stack size (# of OS_STK wide entries) */
|
||||
#define OS_TASK_STAT_STK_SIZE 128 /* Statistics task stack size (# of OS_STK wide entries) */
|
||||
#define OS_TASK_IDLE_STK_SIZE 128 /* Idle task stack size (# of OS_STK wide entries) */
|
||||
|
||||
|
||||
/* --------------------- TASK MANAGEMENT ---------------------- */
|
||||
#define OS_TASK_CHANGE_PRIO_EN 0 /* Include code for OSTaskChangePrio() */
|
||||
#define OS_TASK_CREATE_EN 1 /* Include code for OSTaskCreate() */
|
||||
#define OS_TASK_CREATE_EXT_EN 0 /* Include code for OSTaskCreateExt() */
|
||||
#define OS_TASK_DEL_EN 1 /* Include code for OSTaskDel() */
|
||||
#define OS_TASK_NAME_SIZE 16 /* Determine the size of a task name */
|
||||
#define OS_TASK_PROFILE_EN 0 /* Include variables in OS_TCB for profiling */
|
||||
#define OS_TASK_QUERY_EN 0 /* Include code for OSTaskQuery() */
|
||||
#define OS_TASK_STAT_EN 0 /* Enable (1) or Disable(0) the statistics task */
|
||||
#define OS_TASK_STAT_STK_CHK_EN 0 /* Check task stacks from statistic task */
|
||||
#define OS_TASK_SUSPEND_EN 0 /* Include code for OSTaskSuspend() and OSTaskResume() */
|
||||
#define OS_TASK_SW_HOOK_EN 1 /* Include code for OSTaskSwHook() */
|
||||
|
||||
|
||||
/* ----------------------- EVENT FLAGS ------------------------ */
|
||||
#define OS_FLAG_EN 0 /* Enable (1) or Disable (0) code generation for EVENT FLAGS */
|
||||
#define OS_FLAG_ACCEPT_EN 1 /* Include code for OSFlagAccept() */
|
||||
#define OS_FLAG_DEL_EN 1 /* Include code for OSFlagDel() */
|
||||
#define OS_FLAG_NAME_SIZE 16 /* Determine the size of the name of an event flag group */
|
||||
#define OS_FLAGS_NBITS 16 /* Size in #bits of OS_FLAGS data type (8, 16 or 32) */
|
||||
#define OS_FLAG_QUERY_EN 1 /* Include code for OSFlagQuery() */
|
||||
#define OS_FLAG_WAIT_CLR_EN 1 /* Include code for Wait on Clear EVENT FLAGS */
|
||||
|
||||
|
||||
/* -------------------- MESSAGE MAILBOXES --------------------- */
|
||||
#define OS_MBOX_EN 1 /* Enable (1) or Disable (0) code generation for MAILBOXES */
|
||||
#define OS_MBOX_ACCEPT_EN 1 /* Include code for OSMboxAccept() */
|
||||
#define OS_MBOX_DEL_EN 1 /* Include code for OSMboxDel() */
|
||||
#define OS_MBOX_PEND_ABORT_EN 1 /* Include code for OSMboxPendAbort() */
|
||||
#define OS_MBOX_POST_EN 1 /* Include code for OSMboxPost() */
|
||||
#define OS_MBOX_POST_OPT_EN 1 /* Include code for OSMboxPostOpt() */
|
||||
#define OS_MBOX_QUERY_EN 1 /* Include code for OSMboxQuery() */
|
||||
|
||||
|
||||
/* --------------------- MEMORY MANAGEMENT -------------------- */
|
||||
#define OS_MEM_EN 0 /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */
|
||||
#define OS_MEM_NAME_SIZE 16 /* Determine the size of a memory partition name */
|
||||
#define OS_MEM_QUERY_EN 1 /* Include code for OSMemQuery() */
|
||||
|
||||
|
||||
/* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */
|
||||
#define OS_MUTEX_EN 0 /* Enable (1) or Disable (0) code generation for MUTEX */
|
||||
#define OS_MUTEX_ACCEPT_EN 1 /* Include code for OSMutexAccept() */
|
||||
#define OS_MUTEX_DEL_EN 1 /* Include code for OSMutexDel() */
|
||||
#define OS_MUTEX_QUERY_EN 1 /* Include code for OSMutexQuery() */
|
||||
|
||||
|
||||
/* ---------------------- MESSAGE QUEUES ---------------------- */
|
||||
#define OS_Q_EN 0 /* Enable (1) or Disable (0) code generation for QUEUES */
|
||||
#define OS_Q_ACCEPT_EN 1 /* Include code for OSQAccept() */
|
||||
#define OS_Q_DEL_EN 1 /* Include code for OSQDel() */
|
||||
#define OS_Q_FLUSH_EN 1 /* Include code for OSQFlush() */
|
||||
#define OS_Q_PEND_ABORT_EN 1 /* Include code for OSQPendAbort() */
|
||||
#define OS_Q_POST_EN 1 /* Include code for OSQPost() */
|
||||
#define OS_Q_POST_FRONT_EN 1 /* Include code for OSQPostFront() */
|
||||
#define OS_Q_POST_OPT_EN 1 /* Include code for OSQPostOpt() */
|
||||
#define OS_Q_QUERY_EN 1 /* Include code for OSQQuery() */
|
||||
|
||||
|
||||
/* ------------------------ SEMAPHORES ------------------------ */
|
||||
#define OS_SEM_EN 0 /* Enable (1) or Disable (0) code generation for SEMAPHORES */
|
||||
#define OS_SEM_ACCEPT_EN 1 /* Include code for OSSemAccept() */
|
||||
#define OS_SEM_DEL_EN 1 /* Include code for OSSemDel() */
|
||||
#define OS_SEM_PEND_ABORT_EN 1 /* Include code for OSSemPendAbort() */
|
||||
#define OS_SEM_QUERY_EN 1 /* Include code for OSSemQuery() */
|
||||
#define OS_SEM_SET_EN 1 /* Include code for OSSemSet() */
|
||||
|
||||
|
||||
/* --------------------- TIME MANAGEMENT ---------------------- */
|
||||
#define OS_TIME_DLY_HMSM_EN 0 /* Include code for OSTimeDlyHMSM() */
|
||||
#define OS_TIME_DLY_RESUME_EN 0 /* Include code for OSTimeDlyResume() */
|
||||
#define OS_TIME_GET_SET_EN 0 /* Include code for OSTimeGet() and OSTimeSet() */
|
||||
#define OS_TIME_TICK_HOOK_EN 0 /* Include code for OSTimeTickHook() */
|
||||
|
||||
|
||||
/* --------------------- TIMER MANAGEMENT --------------------- */
|
||||
#define OS_TMR_EN 0 /* Enable (1) or Disable (0) code generation for TIMERS */
|
||||
#define OS_TMR_CFG_MAX 16 /* Maximum number of timers */
|
||||
#define OS_TMR_CFG_NAME_SIZE 16 /* Determine the size of a timer name */
|
||||
#define OS_TMR_CFG_WHEEL_SIZE 8 /* Size of timer wheel (#Spokes) */
|
||||
#define OS_TMR_CFG_TICKS_PER_SEC 10 /* Rate at which timer management task runs (Hz) */
|
||||
|
||||
|
||||
#endif
|
262
uCOS-II Template/uCOS-II/Config/os_dbg.c
Normal file
262
uCOS-II Template/uCOS-II/Config/os_dbg.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* DEBUGGER CONSTANTS
|
||||
*
|
||||
* (c) Copyright 2006, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* ARM Cortex-M3 Port
|
||||
*
|
||||
* File : OS_DBG.C
|
||||
* Version : V2.86
|
||||
* By : Jean J. Labrosse
|
||||
*
|
||||
* For : ARMv7M Cortex-M3
|
||||
* Mode : Thumb2
|
||||
* Toolchain : IAR EWARM
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#include <ucos_ii.h>
|
||||
|
||||
#define OS_COMPILER_OPT //__root
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DEBUG DATA
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSDebugEn = OS_DEBUG_EN; /* Debug constants are defined below */
|
||||
|
||||
#if OS_DEBUG_EN > 0
|
||||
|
||||
OS_COMPILER_OPT INT32U const OSEndiannessTest = 0x12345678L; /* Variable to test CPU endianness */
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSEventMax = OS_MAX_EVENTS; /* Number of event control blocks */
|
||||
OS_COMPILER_OPT INT16U const OSEventNameSize = OS_EVENT_NAME_SIZE; /* Size (in bytes) of event names */
|
||||
OS_COMPILER_OPT INT16U const OSEventEn = OS_EVENT_EN;
|
||||
#if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0)
|
||||
OS_COMPILER_OPT INT16U const OSEventSize = sizeof(OS_EVENT); /* Size in Bytes of OS_EVENT */
|
||||
OS_COMPILER_OPT INT16U const OSEventTblSize = sizeof(OSEventTbl); /* Size of OSEventTbl[] in bytes */
|
||||
#else
|
||||
OS_COMPILER_OPT INT16U const OSEventSize = 0;
|
||||
OS_COMPILER_OPT INT16U const OSEventTblSize = 0;
|
||||
#endif
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSFlagEn = OS_FLAG_EN;
|
||||
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
|
||||
OS_COMPILER_OPT INT16U const OSFlagGrpSize = sizeof(OS_FLAG_GRP); /* Size in Bytes of OS_FLAG_GRP */
|
||||
OS_COMPILER_OPT INT16U const OSFlagNodeSize = sizeof(OS_FLAG_NODE); /* Size in Bytes of OS_FLAG_NODE */
|
||||
OS_COMPILER_OPT INT16U const OSFlagWidth = sizeof(OS_FLAGS); /* Width (in bytes) of OS_FLAGS */
|
||||
#else
|
||||
OS_COMPILER_OPT INT16U const OSFlagGrpSize = 0;
|
||||
OS_COMPILER_OPT INT16U const OSFlagNodeSize = 0;
|
||||
OS_COMPILER_OPT INT16U const OSFlagWidth = 0;
|
||||
#endif
|
||||
OS_COMPILER_OPT INT16U const OSFlagMax = OS_MAX_FLAGS;
|
||||
OS_COMPILER_OPT INT16U const OSFlagNameSize = OS_FLAG_NAME_SIZE; /* Size (in bytes) of flag names */
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSLowestPrio = OS_LOWEST_PRIO;
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSMboxEn = OS_MBOX_EN;
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSMemEn = OS_MEM_EN;
|
||||
OS_COMPILER_OPT INT16U const OSMemMax = OS_MAX_MEM_PART; /* Number of memory partitions */
|
||||
OS_COMPILER_OPT INT16U const OSMemNameSize = OS_MEM_NAME_SIZE; /* Size (in bytes) of partition names */
|
||||
#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
|
||||
OS_COMPILER_OPT INT16U const OSMemSize = sizeof(OS_MEM); /* Mem. Partition header sine (bytes) */
|
||||
OS_COMPILER_OPT INT16U const OSMemTblSize = sizeof(OSMemTbl);
|
||||
#else
|
||||
OS_COMPILER_OPT INT16U const OSMemSize = 0;
|
||||
OS_COMPILER_OPT INT16U const OSMemTblSize = 0;
|
||||
#endif
|
||||
OS_COMPILER_OPT INT16U const OSMutexEn = OS_MUTEX_EN;
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSPtrSize = sizeof(void *); /* Size in Bytes of a pointer */
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSQEn = OS_Q_EN;
|
||||
OS_COMPILER_OPT INT16U const OSQMax = OS_MAX_QS; /* Number of queues */
|
||||
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
|
||||
OS_COMPILER_OPT INT16U const OSQSize = sizeof(OS_Q); /* Size in bytes of OS_Q structure */
|
||||
#else
|
||||
OS_COMPILER_OPT INT16U const OSQSize = 0;
|
||||
#endif
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSRdyTblSize = OS_RDY_TBL_SIZE; /* Number of bytes in the ready table */
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSSemEn = OS_SEM_EN;
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSStkWidth = sizeof(OS_STK); /* Size in Bytes of a stack entry */
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSTaskCreateEn = OS_TASK_CREATE_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskCreateExtEn = OS_TASK_CREATE_EXT_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskDelEn = OS_TASK_DEL_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskIdleStkSize = OS_TASK_IDLE_STK_SIZE;
|
||||
OS_COMPILER_OPT INT16U const OSTaskProfileEn = OS_TASK_PROFILE_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskMax = OS_MAX_TASKS + OS_N_SYS_TASKS; /* Total max. number of tasks */
|
||||
OS_COMPILER_OPT INT16U const OSTaskNameSize = OS_TASK_NAME_SIZE; /* Size (in bytes) of task names */
|
||||
OS_COMPILER_OPT INT16U const OSTaskStatEn = OS_TASK_STAT_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskStatStkSize = OS_TASK_STAT_STK_SIZE;
|
||||
OS_COMPILER_OPT INT16U const OSTaskStatStkChkEn = OS_TASK_STAT_STK_CHK_EN;
|
||||
OS_COMPILER_OPT INT16U const OSTaskSwHookEn = OS_TASK_SW_HOOK_EN;
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSTCBPrioTblMax = OS_LOWEST_PRIO + 1; /* Number of entries in OSTCBPrioTbl[] */
|
||||
OS_COMPILER_OPT INT16U const OSTCBSize = sizeof(OS_TCB); /* Size in Bytes of OS_TCB */
|
||||
OS_COMPILER_OPT INT16U const OSTicksPerSec = OS_TICKS_PER_SEC;
|
||||
OS_COMPILER_OPT INT16U const OSTimeTickHookEn = OS_TIME_TICK_HOOK_EN;
|
||||
OS_COMPILER_OPT INT16U const OSVersionNbr = OS_VERSION;
|
||||
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DEBUG DATA
|
||||
* TOTAL DATA SPACE (i.e. RAM) USED BY uC/OS-II
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_DEBUG_EN > 0
|
||||
|
||||
OS_COMPILER_OPT INT16U const OSDataSize = sizeof(OSCtxSwCtr)
|
||||
#if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0)
|
||||
+ sizeof(OSEventFreeList)
|
||||
+ sizeof(OSEventTbl)
|
||||
#endif
|
||||
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
|
||||
+ sizeof(OSFlagTbl)
|
||||
+ sizeof(OSFlagFreeList)
|
||||
#endif
|
||||
#if OS_TASK_STAT_EN > 0
|
||||
+ sizeof(OSCPUUsage)
|
||||
+ sizeof(OSIdleCtrMax)
|
||||
+ sizeof(OSIdleCtrRun)
|
||||
+ sizeof(OSStatRdy)
|
||||
+ sizeof(OSTaskStatStk)
|
||||
#endif
|
||||
#if OS_TICK_STEP_EN > 0
|
||||
+ sizeof(OSTickStepState)
|
||||
#endif
|
||||
#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
|
||||
+ sizeof(OSMemFreeList)
|
||||
+ sizeof(OSMemTbl)
|
||||
#endif
|
||||
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
|
||||
+ sizeof(OSQFreeList)
|
||||
+ sizeof(OSQTbl)
|
||||
#endif
|
||||
#if OS_TIME_GET_SET_EN > 0
|
||||
+ sizeof(OSTime)
|
||||
#endif
|
||||
+ sizeof(OSIntNesting)
|
||||
+ sizeof(OSLockNesting)
|
||||
+ sizeof(OSPrioCur)
|
||||
+ sizeof(OSPrioHighRdy)
|
||||
+ sizeof(OSRdyGrp)
|
||||
+ sizeof(OSRdyTbl)
|
||||
+ sizeof(OSRunning)
|
||||
+ sizeof(OSTaskCtr)
|
||||
+ sizeof(OSIdleCtr)
|
||||
+ sizeof(OSTaskIdleStk)
|
||||
+ sizeof(OSTCBCur)
|
||||
+ sizeof(OSTCBFreeList)
|
||||
+ sizeof(OSTCBHighRdy)
|
||||
+ sizeof(OSTCBList)
|
||||
+ sizeof(OSTCBPrioTbl)
|
||||
+ sizeof(OSTCBTbl);
|
||||
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS DEBUG INITIALIZAZTION
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_VERSION >= 270 && OS_DEBUG_EN > 0
|
||||
void OSDebugInit (void)
|
||||
{
|
||||
void *ptemp;
|
||||
|
||||
|
||||
ptemp = (void *)&OSDebugEn;
|
||||
|
||||
ptemp = (void *)&OSEndiannessTest;
|
||||
|
||||
ptemp = (void *)&OSEventMax;
|
||||
ptemp = (void *)&OSEventNameSize;
|
||||
ptemp = (void *)&OSEventEn;
|
||||
ptemp = (void *)&OSEventSize;
|
||||
ptemp = (void *)&OSEventTblSize;
|
||||
|
||||
ptemp = (void *)&OSFlagEn;
|
||||
ptemp = (void *)&OSFlagGrpSize;
|
||||
ptemp = (void *)&OSFlagNodeSize;
|
||||
ptemp = (void *)&OSFlagWidth;
|
||||
ptemp = (void *)&OSFlagMax;
|
||||
ptemp = (void *)&OSFlagNameSize;
|
||||
|
||||
ptemp = (void *)&OSLowestPrio;
|
||||
|
||||
ptemp = (void *)&OSMboxEn;
|
||||
|
||||
ptemp = (void *)&OSMemEn;
|
||||
ptemp = (void *)&OSMemMax;
|
||||
ptemp = (void *)&OSMemNameSize;
|
||||
ptemp = (void *)&OSMemSize;
|
||||
ptemp = (void *)&OSMemTblSize;
|
||||
|
||||
ptemp = (void *)&OSMutexEn;
|
||||
|
||||
ptemp = (void *)&OSPtrSize;
|
||||
|
||||
ptemp = (void *)&OSQEn;
|
||||
ptemp = (void *)&OSQMax;
|
||||
ptemp = (void *)&OSQSize;
|
||||
|
||||
ptemp = (void *)&OSRdyTblSize;
|
||||
|
||||
ptemp = (void *)&OSSemEn;
|
||||
|
||||
ptemp = (void *)&OSStkWidth;
|
||||
|
||||
ptemp = (void *)&OSTaskCreateEn;
|
||||
ptemp = (void *)&OSTaskCreateExtEn;
|
||||
ptemp = (void *)&OSTaskDelEn;
|
||||
ptemp = (void *)&OSTaskIdleStkSize;
|
||||
ptemp = (void *)&OSTaskProfileEn;
|
||||
ptemp = (void *)&OSTaskMax;
|
||||
ptemp = (void *)&OSTaskNameSize;
|
||||
ptemp = (void *)&OSTaskStatEn;
|
||||
ptemp = (void *)&OSTaskStatStkSize;
|
||||
ptemp = (void *)&OSTaskStatStkChkEn;
|
||||
ptemp = (void *)&OSTaskSwHookEn;
|
||||
|
||||
ptemp = (void *)&OSTCBPrioTblMax;
|
||||
ptemp = (void *)&OSTCBSize;
|
||||
|
||||
ptemp = (void *)&OSTicksPerSec;
|
||||
ptemp = (void *)&OSTimeTickHookEn;
|
||||
|
||||
ptemp = (void *)&OSVersionNbr;
|
||||
|
||||
ptemp = (void *)&OSDataSize;
|
||||
|
||||
ptemp = ptemp; /* Prevent compiler warning for 'ptemp' not being used! */
|
||||
}
|
||||
#endif
|
115
uCOS-II Template/uCOS-II/Ports/os_cpu.h
Normal file
115
uCOS-II Template/uCOS-II/Ports/os_cpu.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
*
|
||||
*
|
||||
* (c) Copyright 2006, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* ARM Cortex-M3 Port
|
||||
*
|
||||
* File : OS_CPU.H
|
||||
* Version : V2.86
|
||||
* By : Jean J. Labrosse
|
||||
* Brian Nagel
|
||||
*
|
||||
* For : ARMv7M Cortex-M3
|
||||
* Mode : Thumb2
|
||||
* Toolchain : IAR EWARM
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_H
|
||||
#define OS_CPU_H
|
||||
|
||||
|
||||
#ifdef OS_CPU_GLOBALS
|
||||
#define OS_CPU_EXT
|
||||
#else
|
||||
#define OS_CPU_EXT extern
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DATA TYPES
|
||||
* (Compiler Specific)
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
typedef unsigned char BOOLEAN;
|
||||
typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
|
||||
typedef signed char INT8S; /* Signed 8 bit quantity */
|
||||
typedef unsigned short INT16U; /* Unsigned 16 bit quantity */
|
||||
typedef signed short INT16S; /* Signed 16 bit quantity */
|
||||
typedef unsigned int INT32U; /* Unsigned 32 bit quantity */
|
||||
typedef signed int INT32S; /* Signed 32 bit quantity */
|
||||
typedef float FP32; /* Single precision floating point */
|
||||
typedef double FP64; /* Double precision floating point */
|
||||
|
||||
typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */
|
||||
typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* Cortex-M1
|
||||
* Critical Section Management
|
||||
*
|
||||
* Method #1: Disable/Enable interrupts using simple instructions. After critical section, interrupts
|
||||
* will be enabled even if they were disabled before entering the critical section.
|
||||
* NOT IMPLEMENTED
|
||||
*
|
||||
* Method #2: Disable/Enable interrupts by preserving the state of interrupts. In other words, if
|
||||
* interrupts were disabled before entering the critical section, they will be disabled when
|
||||
* leaving the critical section.
|
||||
* NOT IMPLEMENTED
|
||||
*
|
||||
* Method #3: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
|
||||
* would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
|
||||
* disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
|
||||
* disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
|
||||
* into the CPU's status register.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#define OS_CRITICAL_METHOD 3
|
||||
|
||||
#if OS_CRITICAL_METHOD == 3
|
||||
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
|
||||
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* Cortex-M3 Miscellaneous
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on ARM */
|
||||
|
||||
#define OS_TASK_SW() OSCtxSw()
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* PROTOTYPES
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_CRITICAL_METHOD == 3 /* See OS_CPU_A.ASM */
|
||||
OS_CPU_SR OS_CPU_SR_Save(void);
|
||||
void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
|
||||
#endif
|
||||
|
||||
void OSCtxSw(void);
|
||||
void OSIntCtxSw(void);
|
||||
void OSStartHighRdy(void);
|
||||
|
||||
void PendSV_Handler(void);
|
||||
|
||||
// /* See OS_CPU_C.C */
|
||||
//void OS_CPU_SysTickHandler(void);
|
||||
//void OS_CPU_SysTickInit(void);
|
||||
|
||||
/* See BSP.C */
|
||||
//INT32U OS_CPU_SysTickClkFreq(void);
|
||||
#endif
|
241
uCOS-II Template/uCOS-II/Ports/os_cpu_a.asm
Normal file
241
uCOS-II Template/uCOS-II/Ports/os_cpu_a.asm
Normal file
@@ -0,0 +1,241 @@
|
||||
;********************************************************************************************************
|
||||
; uC/OS-II
|
||||
; The Real-Time Kernel
|
||||
;
|
||||
; (c) Copyright 1992-2006, Micrium, Weston, FL
|
||||
; All Rights Reserved
|
||||
;
|
||||
; ARM Cortex-M3 Port
|
||||
;
|
||||
; File : OS_CPU_A.ASM
|
||||
; Version : V2.86
|
||||
; By : Jean J. Labrosse
|
||||
; Brian Nagel
|
||||
;
|
||||
; For : ARMv7M Cortex-M3
|
||||
; Mode : Thumb2
|
||||
; Toolchain : IAR EWARM
|
||||
;********************************************************************************************************
|
||||
|
||||
;********************************************************************************************************
|
||||
; PUBLIC FUNCTIONS
|
||||
;********************************************************************************************************
|
||||
|
||||
EXTERN OSRunning ; External references
|
||||
EXTERN OSPrioCur
|
||||
EXTERN OSPrioHighRdy
|
||||
EXTERN OSTCBCur
|
||||
EXTERN OSTCBHighRdy
|
||||
EXTERN OSIntNesting
|
||||
EXTERN OSIntExit
|
||||
EXTERN OSTaskSwHook
|
||||
|
||||
|
||||
EXPORT OS_CPU_SR_Save ; Functions declared in this file
|
||||
EXPORT OS_CPU_SR_Restore
|
||||
EXPORT OSStartHighRdy
|
||||
EXPORT OSCtxSw
|
||||
EXPORT OSIntCtxSw
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
;********************************************************************************************************
|
||||
; EQUATES
|
||||
;********************************************************************************************************
|
||||
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register.
|
||||
NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14).
|
||||
NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest).
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception.
|
||||
|
||||
;********************************************************************************************************
|
||||
; CODE GENERATION DIRECTIVES
|
||||
;********************************************************************************************************
|
||||
|
||||
;RSEG CODE:CODE:NOROOT(2)
|
||||
AREA |.text|,CODE,READONLY,ALIGN = 2
|
||||
|
||||
thumb
|
||||
require8
|
||||
preserve8
|
||||
|
||||
|
||||
;********************************************************************************************************
|
||||
; CRITICAL SECTION METHOD 3 FUNCTIONS
|
||||
;
|
||||
; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
|
||||
; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
|
||||
; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
|
||||
; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
|
||||
; into the CPU's status register.
|
||||
;
|
||||
; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
|
||||
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
|
||||
;
|
||||
;
|
||||
; Note(s) : 1) These functions are used in general like this:
|
||||
;
|
||||
; void Task (void *p_arg)
|
||||
; {
|
||||
; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
; OS_CPU_SR cpu_sr;
|
||||
; #endif
|
||||
;
|
||||
; :
|
||||
; :
|
||||
; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */
|
||||
; :
|
||||
; :
|
||||
; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */
|
||||
; :
|
||||
; :
|
||||
; }
|
||||
;********************************************************************************************************
|
||||
|
||||
OS_CPU_SR_Save
|
||||
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
OS_CPU_SR_Restore
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
;********************************************************************************************************
|
||||
; 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 OSRunning to TRUE;
|
||||
; d) Trigger PendSV exception;
|
||||
; e) Enable interrupts (tasks will run with interrupts enabled).
|
||||
;********************************************************************************************************
|
||||
|
||||
OSStartHighRdy
|
||||
LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
|
||||
LDR R1, =NVIC_PENDSV_PRI
|
||||
STRB R1, [R0]
|
||||
|
||||
MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
|
||||
MSR PSP, R0
|
||||
|
||||
LDR R0, =OSRunning ; OSRunning = TRUE
|
||||
MOVS R1, #1
|
||||
STRB R1, [R0]
|
||||
|
||||
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)
|
||||
; void OSCtxSw(void)
|
||||
;
|
||||
; 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.
|
||||
;********************************************************************************************************
|
||||
|
||||
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)
|
||||
; void OSIntCtxSw(void)
|
||||
;
|
||||
; Notes: 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.
|
||||
;********************************************************************************************************
|
||||
|
||||
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 PendSV_Handler(void)
|
||||
;
|
||||
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
|
||||
; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the
|
||||
; processor context on any exception, and restores same on return from exception. So only
|
||||
; saving of R4-R11 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) Save remaining regs r4-r11 on process stack;
|
||||
; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
|
||||
; d) Call OSTaskSwHook();
|
||||
; e) Get current high priority, OSPrioCur = OSPrioHighRdy;
|
||||
; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
|
||||
; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
|
||||
; h) Restore R4-R11 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) OSTCBCur points to the OS_TCB of the task to suspend
|
||||
; OSTCBHighRdy 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).
|
||||
;********************************************************************************************************
|
||||
|
||||
PendSV_Handler
|
||||
CPSID I ; Prevent interruption during context switch
|
||||
MRS R0, PSP ; PSP is process stack pointer
|
||||
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
|
||||
|
||||
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
|
||||
STM R0, {R4-R11}
|
||||
|
||||
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
|
||||
LDR R1, [R1]
|
||||
STR R0, [R1] ; R0 is SP of process being switched out
|
||||
|
||||
; At this point, entire context of process has been saved
|
||||
OS_CPU_PendSVHandler_nosave
|
||||
PUSH {R14} ; Save LR exc_return value
|
||||
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
|
||||
BLX R0
|
||||
POP {R14}
|
||||
|
||||
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
|
||||
LDR R1, =OSPrioHighRdy
|
||||
LDRB R2, [R1]
|
||||
STRB R2, [R0]
|
||||
|
||||
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
|
||||
LDR R1, =OSTCBHighRdy
|
||||
LDR R2, [R1]
|
||||
STR R2, [R0]
|
||||
|
||||
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
|
||||
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
|
||||
ADDS R0, R0, #0x20
|
||||
MSR PSP, R0 ; Load PSP with new process SP
|
||||
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
|
||||
CPSIE I
|
||||
BX LR ; Exception return will restore remaining context
|
||||
|
||||
END
|
368
uCOS-II Template/uCOS-II/Ports/os_cpu_c.c
Normal file
368
uCOS-II Template/uCOS-II/Ports/os_cpu_c.c
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
*
|
||||
*
|
||||
* (c) Copyright 2006, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* ARM Cortex-M3 Port
|
||||
*
|
||||
* File : OS_CPU_C.C
|
||||
* Version : V2.86
|
||||
* By : Jean J. Labrosse
|
||||
* Brian Nagel
|
||||
*
|
||||
* For : ARMv7M Cortex-M3
|
||||
* Mode : Thumb2
|
||||
* Toolchain : IAR EWARM
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#define OS_CPU_GLOBALS
|
||||
#include <ucos_ii.h>
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* LOCAL VARIABLES
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_TMR_EN > 0
|
||||
static INT16U OSTmrCtr;
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* SYS TICK DEFINES
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
//#define OS_CPU_CM3_NVIC_ST_CTRL (*((volatile INT32U *)0xE000E010)) /* SysTick Ctrl & Status Reg. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_RELOAD (*((volatile INT32U *)0xE000E014)) /* SysTick Reload Value Reg. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018)) /* SysTick Current Value Reg. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_CAL (*((volatile INT32U *)0xE000E01C)) /* SysTick Cal Value Reg. */
|
||||
//#define OS_CPU_CM3_NVIC_PRIO_ST (*((volatile INT8U *)0xE000ED23)) /* SysTick Handler Prio Reg. */
|
||||
|
||||
//#define OS_CPU_CM3_NVIC_ST_CTRL_COUNT 0x00010000 /* Count flag. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC 0x00000004 /* Clock Source. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_CTRL_INTEN 0x00000002 /* Interrupt enable. */
|
||||
//#define OS_CPU_CM3_NVIC_ST_CTRL_ENABLE 0x00000001 /* Counter mode. */
|
||||
//#define OS_CPU_CM3_NVIC_PRIO_MIN 0xFF /* Min handler prio. */
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS INITIALIZATION HOOK
|
||||
* (BEGINNING)
|
||||
*
|
||||
* Description: This function is called by OSInit() at the beginning of OSInit().
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Note(s) : 1) Interrupts should be disabled during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
|
||||
void OSInitHookBegin (void)
|
||||
{
|
||||
#if OS_TMR_EN > 0
|
||||
OSTmrCtr = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS INITIALIZATION HOOK
|
||||
* (END)
|
||||
*
|
||||
* Description: This function is called by OSInit() at the end of OSInit().
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Note(s) : 1) Interrupts should be disabled during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
|
||||
void OSInitHookEnd (void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* TASK CREATION HOOK
|
||||
*
|
||||
* Description: This function is called when a task is created.
|
||||
*
|
||||
* Arguments : ptcb is a pointer to the task control block of the task being created.
|
||||
*
|
||||
* Note(s) : 1) Interrupts are disabled during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0
|
||||
void OSTaskCreateHook (OS_TCB *ptcb)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TaskCreateHook(ptcb);
|
||||
#else
|
||||
(void)ptcb; /* Prevent compiler warning */
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* TASK DELETION HOOK
|
||||
*
|
||||
* Description: This function is called when a task is deleted.
|
||||
*
|
||||
* Arguments : ptcb is a pointer to the task control block of the task being deleted.
|
||||
*
|
||||
* Note(s) : 1) Interrupts are disabled during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0
|
||||
void OSTaskDelHook (OS_TCB *ptcb)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TaskDelHook(ptcb);
|
||||
#else
|
||||
(void)ptcb; /* Prevent compiler warning */
|
||||
#endif
|
||||
}
|
||||
#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) : 1) Interrupts are enabled during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
|
||||
void OSTaskIdleHook (void)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TaskIdleHook();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* STATISTIC TASK HOOK
|
||||
*
|
||||
* Description: This function is called every second by uC/OS-II's statistics task. This allows your
|
||||
* application to add functionality to the statistics task.
|
||||
*
|
||||
* Arguments : none
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_CPU_HOOKS_EN > 0
|
||||
void OSTaskStatHook (void)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TaskStatHook();
|
||||
#endif
|
||||
}
|
||||
#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 : task is a pointer to the task code
|
||||
*
|
||||
* p_arg is a pointer to a user supplied data area that will be passed to the task
|
||||
* when the task first executes.
|
||||
*
|
||||
* ptos is a pointer to the top of stack. It is assumed that 'ptos' points to
|
||||
* a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then
|
||||
* 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if
|
||||
* OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
|
||||
* of the stack.
|
||||
*
|
||||
* opt specifies options that can be used to alter the behavior of OSTaskStkInit().
|
||||
* (see uCOS_II.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 your task starts executing.
|
||||
* 2) All tasks run in Thread mode, using process stack.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
|
||||
{
|
||||
OS_STK *stk;
|
||||
|
||||
|
||||
(void)opt; /* 'opt' is not used, prevent warning */
|
||||
stk = ptos; /* Load stack pointer */
|
||||
|
||||
/* Registers stacked as if auto-saved on exception */
|
||||
*(stk) = (INT32U)0x01000000L; /* xPSR */
|
||||
*(--stk) = (INT32U)task; /* Entry Point */
|
||||
*(--stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/
|
||||
*(--stk) = (INT32U)0x12121212L; /* R12 */
|
||||
*(--stk) = (INT32U)0x03030303L; /* R3 */
|
||||
*(--stk) = (INT32U)0x02020202L; /* R2 */
|
||||
*(--stk) = (INT32U)0x01010101L; /* R1 */
|
||||
*(--stk) = (INT32U)p_arg; /* R0 : argument */
|
||||
|
||||
/* Remaining registers saved on process stack */
|
||||
*(--stk) = (INT32U)0x11111111L; /* R11 */
|
||||
*(--stk) = (INT32U)0x10101010L; /* R10 */
|
||||
*(--stk) = (INT32U)0x09090909L; /* R9 */
|
||||
*(--stk) = (INT32U)0x08080808L; /* R8 */
|
||||
*(--stk) = (INT32U)0x07070707L; /* R7 */
|
||||
*(--stk) = (INT32U)0x06060606L; /* R6 */
|
||||
*(--stk) = (INT32U)0x05050505L; /* R5 */
|
||||
*(--stk) = (INT32U)0x04040404L; /* R4 */
|
||||
|
||||
return (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 'OSTCBHighRdy' points to the TCB of the task that
|
||||
* will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the
|
||||
* task being switched out (i.e. the preempted task).
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
|
||||
void OSTaskSwHook (void)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TaskSwHook();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS_TCBInit() HOOK
|
||||
*
|
||||
* Description: This function is called by OS_TCBInit() after setting up most of the TCB.
|
||||
*
|
||||
* Arguments : ptcb is a pointer to the TCB of the task being created.
|
||||
*
|
||||
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
|
||||
void OSTCBInitHook (OS_TCB *ptcb)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TCBInitHook(ptcb);
|
||||
#else
|
||||
(void)ptcb; /* Prevent compiler warning */
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* TICK HOOK
|
||||
*
|
||||
* Description: This function is called every tick.
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
#if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)
|
||||
void OSTimeTickHook (void)
|
||||
{
|
||||
#if OS_APP_HOOKS_EN > 0
|
||||
App_TimeTickHook();
|
||||
#endif
|
||||
|
||||
#if OS_TMR_EN > 0
|
||||
OSTmrCtr++;
|
||||
if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) {
|
||||
OSTmrCtr = 0;
|
||||
OSTmrSignal();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS_CPU_SysTickHandler()
|
||||
*
|
||||
* Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick
|
||||
* interrupt.
|
||||
*
|
||||
* Arguments : none.
|
||||
*
|
||||
* Note(s) : 1) This function MUST be placed on entry 15 of the Cortex-M3 vector table.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
//void OS_CPU_SysTickHandler (void)
|
||||
//{
|
||||
// OS_CPU_SR cpu_sr;
|
||||
|
||||
|
||||
// OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
|
||||
// OSIntNesting++;
|
||||
// OS_EXIT_CRITICAL();
|
||||
|
||||
// OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
|
||||
|
||||
// OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
|
||||
//}
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* OS_CPU_SysTickInit()
|
||||
*
|
||||
* Description: Initialize the SysTick.
|
||||
*
|
||||
* Arguments : none.
|
||||
*
|
||||
* Note(s) : 1) This function MUST be called after OSStart() & after processor initialization.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
//extern INT32U SystemCoreClock;
|
||||
|
||||
//void OS_CPU_SysTickInit (void)
|
||||
//{
|
||||
// INT32U cnts;
|
||||
|
||||
|
||||
// //cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC;
|
||||
// cnts = SystemCoreClock / OS_TICKS_PER_SEC;
|
||||
//
|
||||
// OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
|
||||
// /* Set prio of SysTick handler to min prio. */
|
||||
// OS_CPU_CM3_NVIC_PRIO_ST = OS_CPU_CM3_NVIC_PRIO_MIN;
|
||||
// /* Enable timer. */
|
||||
// OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
|
||||
// /* Enable timer interrupt. */
|
||||
// OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
|
||||
//}
|
2020
uCOS-II Template/uCOS-II/Source/os_core.c
Normal file
2020
uCOS-II Template/uCOS-II/Source/os_core.c
Normal file
File diff suppressed because it is too large
Load Diff
1174
uCOS-II Template/uCOS-II/Source/os_flag.c
Normal file
1174
uCOS-II Template/uCOS-II/Source/os_flag.c
Normal file
File diff suppressed because it is too large
Load Diff
629
uCOS-II Template/uCOS-II/Source/os_mbox.c
Normal file
629
uCOS-II Template/uCOS-II/Source/os_mbox.c
Normal file
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* MESSAGE MAILBOX MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_MBOX.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
#if OS_MBOX_EN > 0
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ACCEPT MESSAGE FROM MAILBOX
|
||||
*
|
||||
* Description: This function checks the mailbox to see if a message is available. Unlike OSMboxPend(),
|
||||
* OSMboxAccept() does not suspend the calling task if a message is not available.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block
|
||||
*
|
||||
* Returns : != (void *)0 is the message in the mailbox if one is available. The mailbox is cleared
|
||||
* so the next time OSMboxAccept() is called, the mailbox will be empty.
|
||||
* == (void *)0 if the mailbox is empty or,
|
||||
* if 'pevent' is a NULL pointer or,
|
||||
* if you didn't pass the proper event pointer.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_ACCEPT_EN > 0
|
||||
void *OSMboxAccept (OS_EVENT *pevent)
|
||||
{
|
||||
void *pmsg;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return ((void *)0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
return ((void *)0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pmsg = pevent->OSEventPtr;
|
||||
pevent->OSEventPtr = (void *)0; /* Clear the mailbox */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (pmsg); /* Return the message received (or NULL) */
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* CREATE A MESSAGE MAILBOX
|
||||
*
|
||||
* Description: This function creates a message mailbox if free event control blocks are available.
|
||||
*
|
||||
* Arguments : pmsg is a pointer to a message that you wish to deposit in the mailbox. If
|
||||
* you set this value to the NULL pointer (i.e. (void *)0) then the mailbox
|
||||
* will be considered empty.
|
||||
*
|
||||
* Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the
|
||||
* created mailbox
|
||||
* == (OS_EVENT *)0 if no event control blocks were available
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_EVENT *OSMboxCreate (void *pmsg)
|
||||
{
|
||||
OS_EVENT *pevent;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pevent = OSEventFreeList; /* Get next free event control block */
|
||||
if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
|
||||
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if (pevent != (OS_EVENT *)0) {
|
||||
pevent->OSEventType = OS_EVENT_TYPE_MBOX;
|
||||
pevent->OSEventCnt = 0;
|
||||
pevent->OSEventPtr = pmsg; /* Deposit message in event control block */
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?';
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
OS_EventWaitListInit(pevent);
|
||||
}
|
||||
return (pevent); /* Return pointer to event control block */
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DELETE A MAIBOX
|
||||
*
|
||||
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* mailbox.
|
||||
*
|
||||
* opt determines delete options as follows:
|
||||
* opt == OS_DEL_NO_PEND Delete the mailbox ONLY if no task pending
|
||||
* opt == OS_DEL_ALWAYS Deletes the mailbox even if tasks are waiting.
|
||||
* In this case, all the tasks pending will be readied.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
* OS_ERR_NONE The call was successful and the mailbox was deleted
|
||||
* OS_ERR_DEL_ISR If you attempted to delete the mailbox from an ISR
|
||||
* OS_ERR_INVALID_OPT An invalid option was specified
|
||||
* OS_ERR_TASK_WAITING One or more tasks were waiting on the mailbox
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* Returns : pevent upon error
|
||||
* (OS_EVENT *)0 if the mailbox was successfully deleted.
|
||||
*
|
||||
* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
|
||||
* the mailbox MUST check the return code of OSMboxPend().
|
||||
* 2) OSMboxAccept() callers will not know that the intended mailbox has been deleted!
|
||||
* 3) This call can potentially disable interrupts for a long time. The interrupt disable
|
||||
* time is directly proportional to the number of tasks waiting on the mailbox.
|
||||
* 4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in
|
||||
* applications where the mailbox is used for mutual exclusion because the resource(s)
|
||||
* will no longer be guarded by the mailbox.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_DEL_EN > 0
|
||||
OS_EVENT *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
BOOLEAN tasks_waiting;
|
||||
OS_EVENT *pevent_return;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (pevent);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (pevent);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (pevent);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
|
||||
return (pevent);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on mailbox */
|
||||
tasks_waiting = OS_TRUE; /* Yes */
|
||||
} else {
|
||||
tasks_waiting = OS_FALSE; /* No */
|
||||
}
|
||||
switch (opt) {
|
||||
case OS_DEL_NO_PEND: /* Delete mailbox only if no task waiting */
|
||||
if (tasks_waiting == OS_FALSE) {
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_TASK_WAITING;
|
||||
pevent_return = pevent;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_DEL_ALWAYS: /* Always delete the mailbox */
|
||||
while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for mailbox */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_OK);
|
||||
}
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
}
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */
|
||||
break;
|
||||
|
||||
default:
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_INVALID_OPT;
|
||||
pevent_return = pevent;
|
||||
break;
|
||||
}
|
||||
return (pevent_return);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* PEND ON MAILBOX FOR A MESSAGE
|
||||
*
|
||||
* Description: This function waits for a message to be sent to a mailbox
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
|
||||
*
|
||||
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
|
||||
* wait for a message to arrive at the mailbox up to the amount of time
|
||||
* specified by this argument. If you specify 0, however, your task will wait
|
||||
* forever at the specified mailbox or, until a message arrives.
|
||||
*
|
||||
* perr 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_TIMEOUT A message was not received within the specified 'timeout'.
|
||||
* OS_ERR_PEND_ABORT The wait on the mailbox was aborted.
|
||||
* OS_ERR_EVENT_TYPE Invalid event type
|
||||
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
|
||||
* would lead to a suspension.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
|
||||
*
|
||||
* Returns : != (void *)0 is a pointer to the message received
|
||||
* == (void *)0 if no message was received or,
|
||||
* if 'pevent' is a NULL pointer or,
|
||||
* if you didn't pass the proper pointer to the event control block.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
/*$PAGE*/
|
||||
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
|
||||
{
|
||||
void *pmsg;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return ((void *)0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return ((void *)0);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
|
||||
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
|
||||
return ((void *)0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pmsg = pevent->OSEventPtr;
|
||||
if (pmsg != (void *)0) { /* See if there is already a message */
|
||||
pevent->OSEventPtr = (void *)0; /* Clear the mailbox */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (pmsg); /* Return the message received (or NULL) */
|
||||
}
|
||||
OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
|
||||
OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */
|
||||
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find next highest priority task ready to run */
|
||||
OS_ENTER_CRITICAL();
|
||||
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
|
||||
case OS_STAT_PEND_OK:
|
||||
pmsg = OSTCBCur->OSTCBMsg;
|
||||
*perr = OS_ERR_NONE;
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_ABORT:
|
||||
pmsg = (void *)0;
|
||||
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_TO:
|
||||
default:
|
||||
OS_EventTaskRemove(OSTCBCur, pevent);
|
||||
pmsg = (void *)0;
|
||||
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
|
||||
break;
|
||||
}
|
||||
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
|
||||
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
|
||||
#if (OS_EVENT_MULTI_EN > 0)
|
||||
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
|
||||
#endif
|
||||
OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (pmsg); /* Return received message */
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ABORT WAITING ON A MESSAGE MAILBOX
|
||||
*
|
||||
* Description: This function aborts & readies any tasks currently waiting on a mailbox. This function
|
||||
* should be used to fault-abort the wait on the mailbox, rather than to normally signal
|
||||
* the mailbox via OSMboxPost() or OSMboxPostOpt().
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox.
|
||||
*
|
||||
* opt determines the type of ABORT performed:
|
||||
* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
|
||||
* mailbox
|
||||
* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
|
||||
* mailbox
|
||||
*
|
||||
* perr is a pointer to where an error message will be deposited. Possible error
|
||||
* messages are:
|
||||
*
|
||||
* OS_ERR_NONE No tasks were waiting on the mailbox.
|
||||
* OS_ERR_PEND_ABORT At least one task waiting on the mailbox was readied
|
||||
* and informed of the aborted wait; check return value
|
||||
* for the number of tasks whose wait on the mailbox
|
||||
* was aborted.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* Returns : == 0 if no tasks were waiting on the mailbox, or upon error.
|
||||
* > 0 if one or more tasks waiting on the mailbox are now readied and informed.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_PEND_ABORT_EN > 0
|
||||
INT8U OSMboxPendAbort (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
INT8U nbr_tasks;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task waiting on mailbox? */
|
||||
nbr_tasks = 0;
|
||||
switch (opt) {
|
||||
case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */
|
||||
while (pevent->OSEventGrp != 0) { /* Yes, ready ALL tasks waiting on mailbox */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_PEND_OPT_NONE:
|
||||
default: /* No, ready HPT waiting on mailbox */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
break;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find HPT ready to run */
|
||||
*perr = OS_ERR_PEND_ABORT;
|
||||
return (nbr_tasks);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (0); /* No tasks waiting on mailbox */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST MESSAGE TO A MAILBOX
|
||||
*
|
||||
* Description: This function sends a message to a mailbox
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
|
||||
*
|
||||
* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one
|
||||
* message at a time and thus, the message MUST be consumed before you
|
||||
* are allowed to send another one.
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
|
||||
*
|
||||
* Note(s) : 1) HPT means Highest Priority Task
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_POST_EN > 0
|
||||
INT8U OSMboxPost (OS_EVENT *pevent, void *pmsg)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (pmsg == (void *)0) { /* Make sure we are not posting a NULL pointer */
|
||||
return (OS_ERR_POST_NULL_PTR);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task pending on mailbox */
|
||||
/* Ready HPT waiting on event */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_MBOX_FULL);
|
||||
}
|
||||
pevent->OSEventPtr = pmsg; /* Place message in mailbox */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST MESSAGE TO A MAILBOX
|
||||
*
|
||||
* Description: This function sends a message to a mailbox
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
|
||||
*
|
||||
* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer.
|
||||
*
|
||||
* opt determines the type of POST performed:
|
||||
* OS_POST_OPT_NONE POST to a single waiting task
|
||||
* (Identical to OSMboxPost())
|
||||
* OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the mailbox
|
||||
*
|
||||
* OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one
|
||||
* message at a time and thus, the message MUST be consumed before you
|
||||
* are allowed to send another one.
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
|
||||
*
|
||||
* Note(s) : 1) HPT means Highest Priority Task
|
||||
*
|
||||
* Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the
|
||||
* interrupt disable time is proportional to the number of tasks waiting on the mailbox.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_POST_OPT_EN > 0
|
||||
INT8U OSMboxPostOpt (OS_EVENT *pevent, void *pmsg, INT8U opt)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (pmsg == (void *)0) { /* Make sure we are not posting a NULL pointer */
|
||||
return (OS_ERR_POST_NULL_PTR);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task pending on mailbox */
|
||||
if ((opt & OS_POST_OPT_BROADCAST) != 0x00) { /* Do we need to post msg to ALL waiting tasks ? */
|
||||
while (pevent->OSEventGrp != 0) { /* Yes, Post to ALL tasks waiting on mailbox */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
|
||||
}
|
||||
} else { /* No, Post to HPT waiting on mbox */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if ((opt & OS_POST_OPT_NO_SCHED) == 0) { /* See if scheduler needs to be invoked */
|
||||
OS_Sched(); /* Find HPT ready to run */
|
||||
}
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_MBOX_FULL);
|
||||
}
|
||||
pevent->OSEventPtr = pmsg; /* Place message in mailbox */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUERY A MESSAGE MAILBOX
|
||||
*
|
||||
* Description: This function obtains information about a message mailbox.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
|
||||
*
|
||||
* p_mbox_data is a pointer to a structure that will contain information about the message
|
||||
* mailbox.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mailbox.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_PDATA_NULL If 'p_mbox_data' is a NULL pointer
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MBOX_QUERY_EN > 0
|
||||
INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *p_mbox_data)
|
||||
{
|
||||
INT8U i;
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
INT8U *psrc;
|
||||
INT8U *pdest;
|
||||
#else
|
||||
INT16U *psrc;
|
||||
INT16U *pdest;
|
||||
#endif
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (p_mbox_data == (OS_MBOX_DATA *)0) { /* Validate 'p_mbox_data' */
|
||||
return (OS_ERR_PDATA_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
p_mbox_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */
|
||||
psrc = &pevent->OSEventTbl[0];
|
||||
pdest = &p_mbox_data->OSEventTbl[0];
|
||||
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
|
||||
*pdest++ = *psrc++;
|
||||
}
|
||||
p_mbox_data->OSMsg = pevent->OSEventPtr; /* Get message from mailbox */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif /* OS_MBOX_QUERY_EN */
|
||||
#endif /* OS_MBOX_EN */
|
434
uCOS-II Template/uCOS-II/Source/os_mem.c
Normal file
434
uCOS-II Template/uCOS-II/Source/os_mem.c
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* MEMORY MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_MEM.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* CREATE A MEMORY PARTITION
|
||||
*
|
||||
* Description : Create a fixed-sized memory partition that will be managed by uC/OS-II.
|
||||
*
|
||||
* Arguments : addr is the starting address of the memory partition
|
||||
*
|
||||
* nblks is the number of memory blocks to create from the partition.
|
||||
*
|
||||
* blksize is the size (in bytes) of each block in the memory partition.
|
||||
*
|
||||
* perr 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_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_PART no free partitions available
|
||||
* OS_ERR_MEM_INVALID_BLKS user specified an invalid number of blocks (must be >= 2)
|
||||
* 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
|
||||
* Returns : != (OS_MEM *)0 is the partition was created
|
||||
* == (OS_MEM *)0 if the partition was not created because of invalid arguments or, no
|
||||
* free partition is available.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *perr)
|
||||
{
|
||||
OS_MEM *pmem;
|
||||
INT8U *pblk;
|
||||
void **plink;
|
||||
INT32U i;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
if (addr == (void *)0) { /* Must pass a valid address for the memory part.*/
|
||||
*perr = OS_ERR_MEM_INVALID_ADDR;
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
if (((INT32U)addr & (sizeof(void *) - 1)) != 0){ /* Must be pointer size aligned */
|
||||
*perr = OS_ERR_MEM_INVALID_ADDR;
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
if (nblks < 2) { /* Must have at least 2 blocks per partition */
|
||||
*perr = OS_ERR_MEM_INVALID_BLKS;
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */
|
||||
*perr = OS_ERR_MEM_INVALID_SIZE;
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
#endif
|
||||
OS_ENTER_CRITICAL();
|
||||
pmem = OSMemFreeList; /* Get next free memory partition */
|
||||
if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */
|
||||
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */
|
||||
*perr = OS_ERR_MEM_INVALID_PART;
|
||||
return ((OS_MEM *)0);
|
||||
}
|
||||
plink = (void **)addr; /* Create linked list of free memory blocks */
|
||||
pblk = (INT8U *)((INT32U)addr + blksize);
|
||||
for (i = 0; i < (nblks - 1); i++) {
|
||||
*plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */
|
||||
plink = (void **)pblk; /* Position to NEXT block */
|
||||
pblk = (INT8U *)((INT32U)pblk + blksize); /* Point to the FOLLOWING block */
|
||||
}
|
||||
*plink = (void *)0; /* Last memory block points to NULL */
|
||||
pmem->OSMemAddr = addr; /* Store start address of memory partition */
|
||||
pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */
|
||||
pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */
|
||||
pmem->OSMemNBlks = nblks;
|
||||
pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */
|
||||
*perr = OS_ERR_NONE;
|
||||
return (pmem);
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* GET A MEMORY BLOCK
|
||||
*
|
||||
* Description : Get a memory block from a partition
|
||||
*
|
||||
* Arguments : pmem is a pointer to the memory partition control block
|
||||
*
|
||||
* perr 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_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller
|
||||
* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
|
||||
*
|
||||
* Returns : A pointer to a memory block if no error is detected
|
||||
* A pointer to NULL if an error is detected
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void *OSMemGet (OS_MEM *pmem, INT8U *perr)
|
||||
{
|
||||
void *pblk;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
|
||||
*perr = OS_ERR_MEM_INVALID_PMEM;
|
||||
return ((void *)0);
|
||||
}
|
||||
#endif
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pmem->OSMemNFree > 0) { /* See if there are any free memory blocks */
|
||||
pblk = pmem->OSMemFreeList; /* Yes, point to next free memory block */
|
||||
pmem->OSMemFreeList = *(void **)pblk; /* Adjust pointer to new free list */
|
||||
pmem->OSMemNFree--; /* One less memory block in this partition */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE; /* No error */
|
||||
return (pblk); /* Return memory block to caller */
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */
|
||||
return ((void *)0); /* Return NULL pointer to caller */
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* GET THE NAME OF A MEMORY PARTITION
|
||||
*
|
||||
* Description: This function is used to obtain the name assigned to a memory partition.
|
||||
*
|
||||
* Arguments : pmem is a pointer to the memory partition
|
||||
*
|
||||
* pname is a pointer to an ASCII string that will receive the name of the memory partition.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
*
|
||||
* OS_ERR_NONE if the name was copied to 'pname'
|
||||
* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
|
||||
* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname'
|
||||
* OS_ERR_NAME_GET_ISR You called this function from an ISR
|
||||
*
|
||||
* Returns : The length of the string or 0 if 'pmem' is a NULL pointer.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MEM_NAME_SIZE > 1
|
||||
INT8U OSMemNameGet (OS_MEM *pmem, INT8U *pname, INT8U *perr)
|
||||
{
|
||||
INT8U len;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (0);
|
||||
}
|
||||
if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */
|
||||
*perr = OS_ERR_MEM_INVALID_PMEM;
|
||||
return (0);
|
||||
}
|
||||
if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */
|
||||
*perr = OS_ERR_PNAME_NULL;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
|
||||
*perr = OS_ERR_NAME_GET_ISR;
|
||||
return (0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
len = OS_StrCopy(pname, pmem->OSMemName); /* Copy name from OS_MEM */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ASSIGN A NAME TO A MEMORY PARTITION
|
||||
*
|
||||
* Description: This function assigns a name to a memory partition.
|
||||
*
|
||||
* Arguments : pmem is a pointer to the memory partition
|
||||
*
|
||||
* pname is a pointer to an ASCII string that contains the name of the memory partition.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
*
|
||||
* OS_ERR_NONE if the name was copied to 'pname'
|
||||
* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
|
||||
* OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname'
|
||||
* OS_ERR_MEM_NAME_TOO_LONG if the name doesn't fit in the storage area
|
||||
* OS_ERR_NAME_SET_ISR if you called this function from an ISR
|
||||
*
|
||||
* Returns : None
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MEM_NAME_SIZE > 1
|
||||
void OSMemNameSet (OS_MEM *pmem, INT8U *pname, INT8U *perr)
|
||||
{
|
||||
INT8U len;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return;
|
||||
}
|
||||
if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */
|
||||
*perr = OS_ERR_MEM_INVALID_PMEM;
|
||||
return;
|
||||
}
|
||||
if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */
|
||||
*perr = OS_ERR_PNAME_NULL;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
|
||||
*perr = OS_ERR_NAME_SET_ISR;
|
||||
return;
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
len = OS_StrLen(pname); /* Can we fit the string in the storage area? */
|
||||
if (len > (OS_MEM_NAME_SIZE - 1)) { /* No */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_MEM_NAME_TOO_LONG;
|
||||
return;
|
||||
}
|
||||
(void)OS_StrCopy(pmem->OSMemName, pname); /* Yes, copy name to the memory partition header */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* RELEASE A MEMORY BLOCK
|
||||
*
|
||||
* Description : Returns a memory block to a partition
|
||||
*
|
||||
* Arguments : pmem is a pointer to the memory partition control block
|
||||
*
|
||||
* pblk is a pointer to the memory block being released.
|
||||
*
|
||||
* Returns : 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_PMEM if you passed a NULL pointer for 'pmem'
|
||||
* OS_ERR_MEM_INVALID_PBLK if you passed a NULL pointer for the block to release.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
INT8U OSMemPut (OS_MEM *pmem, void *pblk)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
|
||||
return (OS_ERR_MEM_INVALID_PMEM);
|
||||
}
|
||||
if (pblk == (void *)0) { /* Must release a valid block */
|
||||
return (OS_ERR_MEM_INVALID_PBLK);
|
||||
}
|
||||
#endif
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pmem->OSMemNFree >= pmem->OSMemNBlks) { /* Make sure all blocks not already returned */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_MEM_FULL);
|
||||
}
|
||||
*(void **)pblk = pmem->OSMemFreeList; /* Insert released block into free block list */
|
||||
pmem->OSMemFreeList = pblk;
|
||||
pmem->OSMemNFree++; /* One more memory block in this partition */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE); /* Notify caller that memory block was released */
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUERY MEMORY PARTITION
|
||||
*
|
||||
* Description : This function is used to determine the number of free memory blocks and the number of
|
||||
* used memory blocks from a memory partition.
|
||||
*
|
||||
* Arguments : pmem is a pointer to the memory partition control block
|
||||
*
|
||||
* p_mem_data is a pointer to a structure that will contain information about the memory
|
||||
* partition.
|
||||
*
|
||||
* Returns : OS_ERR_NONE if no errors were found.
|
||||
* OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
|
||||
* OS_ERR_MEM_INVALID_PDATA if you passed a NULL pointer to the data recipient.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MEM_QUERY_EN > 0
|
||||
INT8U OSMemQuery (OS_MEM *pmem, OS_MEM_DATA *p_mem_data)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
|
||||
return (OS_ERR_MEM_INVALID_PMEM);
|
||||
}
|
||||
if (p_mem_data == (OS_MEM_DATA *)0) { /* Must release a valid storage area for the data */
|
||||
return (OS_ERR_MEM_INVALID_PDATA);
|
||||
}
|
||||
#endif
|
||||
OS_ENTER_CRITICAL();
|
||||
p_mem_data->OSAddr = pmem->OSMemAddr;
|
||||
p_mem_data->OSFreeList = pmem->OSMemFreeList;
|
||||
p_mem_data->OSBlkSize = pmem->OSMemBlkSize;
|
||||
p_mem_data->OSNBlks = pmem->OSMemNBlks;
|
||||
p_mem_data->OSNFree = pmem->OSMemNFree;
|
||||
OS_EXIT_CRITICAL();
|
||||
p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree;
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif /* OS_MEM_QUERY_EN */
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* INITIALIZE MEMORY PARTITION MANAGER
|
||||
*
|
||||
* Description : This function is called by uC/OS-II 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-II and your application should not call it.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void OS_MemInit (void)
|
||||
{
|
||||
#if OS_MAX_MEM_PART == 1
|
||||
OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */
|
||||
OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list */
|
||||
#if OS_MEM_NAME_SIZE > 1
|
||||
OSMemFreeList->OSMemName[0] = '?'; /* Unknown name */
|
||||
OSMemFreeList->OSMemName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if OS_MAX_MEM_PART >= 2
|
||||
OS_MEM *pmem;
|
||||
INT16U i;
|
||||
|
||||
|
||||
OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */
|
||||
pmem = &OSMemTbl[0]; /* Point to memory control block (MCB) */
|
||||
for (i = 0; i < (OS_MAX_MEM_PART - 1); i++) { /* Init. list of free memory partitions */
|
||||
pmem->OSMemFreeList = (void *)&OSMemTbl[i+1]; /* Chain list of free partitions */
|
||||
#if OS_MEM_NAME_SIZE > 1
|
||||
pmem->OSMemName[0] = '?'; /* Unknown name */
|
||||
pmem->OSMemName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pmem++;
|
||||
}
|
||||
pmem->OSMemFreeList = (void *)0; /* Initialize last node */
|
||||
#if OS_MEM_NAME_SIZE > 1
|
||||
pmem->OSMemName[0] = '?'; /* Unknown name */
|
||||
pmem->OSMemName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
|
||||
OSMemFreeList = &OSMemTbl[0]; /* Point to beginning of free list */
|
||||
#endif
|
||||
}
|
||||
#endif /* OS_MEM_EN */
|
715
uCOS-II Template/uCOS-II/Source/os_mutex.c
Normal file
715
uCOS-II Template/uCOS-II/Source/os_mutex.c
Normal file
@@ -0,0 +1,715 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* MUTUAL EXCLUSION SEMAPHORE MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_MUTEX.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if OS_MUTEX_EN > 0
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* LOCAL CONSTANTS
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#define OS_MUTEX_KEEP_LOWER_8 ((INT16U)0x00FFu)
|
||||
#define OS_MUTEX_KEEP_UPPER_8 ((INT16U)0xFF00u)
|
||||
|
||||
#define OS_MUTEX_AVAILABLE ((INT16U)0x00FFu)
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* LOCAL CONSTANTS
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
static void OSMutex_RdyAtPrio(OS_TCB *ptcb, INT8U prio);
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ACCEPT MUTUAL EXCLUSION SEMAPHORE
|
||||
*
|
||||
* Description: This function checks the mutual exclusion semaphore to see if a resource is available.
|
||||
* Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is
|
||||
* not available or the event did not occur.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block
|
||||
*
|
||||
* perr is a pointer to an error code which will be returned to your application:
|
||||
* OS_ERR_NONE if the call was successful.
|
||||
* OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex
|
||||
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
|
||||
* OS_ERR_PEND_ISR if you called this function from an ISR
|
||||
* OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is
|
||||
* HIGHER (i.e. a lower number) than the PIP. This error
|
||||
* indicates that you did not set the PIP higher (lower
|
||||
* number) than ALL the tasks that compete for the Mutex.
|
||||
* Unfortunately, this is something that could not be
|
||||
* detected when the Mutex is created because we don't know
|
||||
* what tasks will be using the Mutex.
|
||||
*
|
||||
* Returns : == OS_TRUE if the resource is available, the mutual exclusion semaphore is acquired
|
||||
* == OS_FALSE a) if the resource is not available
|
||||
* b) you didn't pass a pointer to a mutual exclusion semaphore
|
||||
* c) you called this function from an ISR
|
||||
*
|
||||
* Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are
|
||||
* intended to be used by tasks only.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MUTEX_ACCEPT_EN > 0
|
||||
BOOLEAN OSMutexAccept (OS_EVENT *pevent, INT8U *perr)
|
||||
{
|
||||
INT8U pip; /* Priority Inheritance Priority (PIP) */
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (OS_FALSE);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (OS_FALSE);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (OS_FALSE);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* Make sure it's not called from an ISR */
|
||||
*perr = OS_ERR_PEND_ISR;
|
||||
return (OS_FALSE);
|
||||
}
|
||||
OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP from mutex */
|
||||
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
|
||||
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */
|
||||
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */
|
||||
pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */
|
||||
if (OSTCBCur->OSTCBPrio <= pip) { /* PIP 'must' have a SMALLER prio ... */
|
||||
OS_EXIT_CRITICAL(); /* ... than current task! */
|
||||
*perr = OS_ERR_PIP_LOWER;
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
}
|
||||
return (OS_TRUE);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (OS_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* CREATE A MUTUAL EXCLUSION SEMAPHORE
|
||||
*
|
||||
* Description: This function creates a mutual exclusion semaphore.
|
||||
*
|
||||
* Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In
|
||||
* other words, when the semaphore is acquired and a higher priority task
|
||||
* attempts to obtain the semaphore then the priority of the task owning the
|
||||
* semaphore is raised to this priority. It is assumed that you will specify
|
||||
* a priority that is LOWER in value than ANY of the tasks competing for the
|
||||
* mutex.
|
||||
*
|
||||
* perr 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 a MUTEX from an ISR
|
||||
* OS_ERR_PRIO_EXIST if a task at the priority inheritance priority
|
||||
* already exist.
|
||||
* OS_ERR_PEVENT_NULL No more event control blocks available.
|
||||
* OS_ERR_PRIO_INVALID if the priority you specify is higher that the
|
||||
* maximum allowed (i.e. > OS_LOWEST_PRIO)
|
||||
*
|
||||
* Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
|
||||
* created mutex.
|
||||
* == (void *)0 if an error is detected.
|
||||
*
|
||||
* Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' are used to hold the priority number
|
||||
* of the task owning the mutex or 0xFF if no task owns the mutex.
|
||||
*
|
||||
* 2) The MOST significant 8 bits of '.OSEventCnt' are used to hold the priority number
|
||||
* to use to reduce priority inversion.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_EVENT *OSMutexCreate (INT8U prio, INT8U *perr)
|
||||
{
|
||||
OS_EVENT *pevent;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((OS_EVENT *)0);
|
||||
}
|
||||
if (prio >= OS_LOWEST_PRIO) { /* Validate PIP */
|
||||
*perr = OS_ERR_PRIO_INVALID;
|
||||
return ((OS_EVENT *)0);
|
||||
}
|
||||
#endif
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_CREATE_ISR; /* ... can't CREATE mutex from an ISR */
|
||||
return ((OS_EVENT *)0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* Mutex priority must not already exist */
|
||||
OS_EXIT_CRITICAL(); /* Task already exist at priority ... */
|
||||
*perr = OS_ERR_PRIO_EXIST; /* ... inheritance priority */
|
||||
return ((OS_EVENT *)0);
|
||||
}
|
||||
OSTCBPrioTbl[prio] = OS_TCB_RESERVED; /* Reserve the table entry */
|
||||
pevent = OSEventFreeList; /* Get next free event control block */
|
||||
if (pevent == (OS_EVENT *)0) { /* See if an ECB was available */
|
||||
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* No, Release the table entry */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_PEVENT_NULL; /* No more event control blocks */
|
||||
return (pevent);
|
||||
}
|
||||
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list */
|
||||
OS_EXIT_CRITICAL();
|
||||
pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
|
||||
pevent->OSEventCnt = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; /* Resource is avail. */
|
||||
pevent->OSEventPtr = (void *)0; /* No task owning the mutex */
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?';
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
OS_EventWaitListInit(pevent);
|
||||
*perr = OS_ERR_NONE;
|
||||
return (pevent);
|
||||
}
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DELETE A MUTEX
|
||||
*
|
||||
* Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mutex.
|
||||
*
|
||||
* opt determines delete options as follows:
|
||||
* opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending
|
||||
* opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting.
|
||||
* In this case, all the tasks pending will be readied.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
* 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_INVALID_OPT An invalid option was specified
|
||||
* OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* Returns : pevent upon error
|
||||
* (OS_EVENT *)0 if the mutex was successfully deleted.
|
||||
*
|
||||
* 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) This call can potentially disable interrupts for a long time. The interrupt disable
|
||||
* time is directly proportional to the number of tasks waiting on the mutex.
|
||||
*
|
||||
* 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the
|
||||
* resource(s) will no longer be guarded by the mutex.
|
||||
*
|
||||
* 4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there
|
||||
* is one) is ready-to-run and is thus NOT pending on another kernel object or
|
||||
* has delayed itself. In other words, if a task owns the mutex being deleted,
|
||||
* that task will be made ready-to-run at its original priority.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MUTEX_DEL_EN
|
||||
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
BOOLEAN tasks_waiting;
|
||||
OS_EVENT *pevent_return;
|
||||
INT8U pip; /* Priority inheritance priority */
|
||||
INT8U prio;
|
||||
OS_TCB *ptcb;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (pevent);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (pevent);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (pevent);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
|
||||
return (pevent);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on mutex */
|
||||
tasks_waiting = OS_TRUE; /* Yes */
|
||||
} else {
|
||||
tasks_waiting = OS_FALSE; /* No */
|
||||
}
|
||||
switch (opt) {
|
||||
case OS_DEL_NO_PEND: /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
|
||||
if (tasks_waiting == OS_FALSE) {
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8);
|
||||
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent;
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_TASK_WAITING;
|
||||
pevent_return = pevent;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_DEL_ALWAYS: /* ALWAYS DELETE THE MUTEX ---------------- */
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP of mutex */
|
||||
prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original prio */
|
||||
ptcb = (OS_TCB *)pevent->OSEventPtr;
|
||||
if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */
|
||||
if (ptcb->OSTCBPrio == pip) { /* See if original prio was changed */
|
||||
OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */
|
||||
}
|
||||
}
|
||||
while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for mutex */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
|
||||
}
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8);
|
||||
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* Free up the PIP */
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
}
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
|
||||
break;
|
||||
|
||||
default:
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_INVALID_OPT;
|
||||
pevent_return = pevent;
|
||||
break;
|
||||
}
|
||||
return (pevent_return);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* PEND ON MUTUAL EXCLUSION SEMAPHORE
|
||||
*
|
||||
* Description: This function waits for a mutual exclusion semaphore.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* 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 specified by this argument.
|
||||
* If you specify 0, however, your task will wait forever at the specified
|
||||
* mutex or, until the resource becomes available.
|
||||
*
|
||||
* perr 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 owns the mutex
|
||||
* OS_ERR_TIMEOUT The mutex was not available within the specified 'timeout'.
|
||||
* OS_ERR_PEND_ABORT The wait on the mutex was aborted.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
|
||||
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
|
||||
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
|
||||
* would lead to a suspension.
|
||||
* OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is
|
||||
* HIGHER (i.e. a lower number) than the PIP. This error
|
||||
* indicates that you did not set the PIP higher (lower
|
||||
* number) than ALL the tasks that compete for the Mutex.
|
||||
* Unfortunately, this is something that could not be
|
||||
* detected when the Mutex is created because we don't know
|
||||
* what tasks will be using the Mutex.
|
||||
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
|
||||
*
|
||||
* Returns : none
|
||||
*
|
||||
* Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex.
|
||||
*
|
||||
* 2) You MUST NOT change the priority of the task that owns the mutex
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
|
||||
{
|
||||
INT8U pip; /* Priority Inheritance Priority (PIP) */
|
||||
INT8U mprio; /* Mutex owner priority */
|
||||
BOOLEAN rdy; /* Flag indicating task was ready */
|
||||
OS_TCB *ptcb;
|
||||
OS_EVENT *pevent2;
|
||||
INT8U y;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return;
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return;
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
|
||||
return;
|
||||
}
|
||||
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
|
||||
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
|
||||
return;
|
||||
}
|
||||
/*$PAGE*/
|
||||
OS_ENTER_CRITICAL();
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get PIP from mutex */
|
||||
/* Is Mutex available? */
|
||||
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
|
||||
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Yes, Acquire the resource */
|
||||
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */
|
||||
pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
|
||||
if (OSTCBCur->OSTCBPrio <= pip) { /* PIP 'must' have a SMALLER prio ... */
|
||||
OS_EXIT_CRITICAL(); /* ... than current task! */
|
||||
*perr = OS_ERR_PIP_LOWER;
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* No, Get priority of mutex owner */
|
||||
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
|
||||
if (ptcb->OSTCBPrio > pip) { /* Need to promote prio of owner?*/
|
||||
if (mprio > OSTCBCur->OSTCBPrio) {
|
||||
y = ptcb->OSTCBY;
|
||||
if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0) { /* See if mutex owner is ready */
|
||||
OSRdyTbl[y] &= ~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/
|
||||
if (OSRdyTbl[y] == 0) { /* ... list at current prio */
|
||||
OSRdyGrp &= ~ptcb->OSTCBBitY;
|
||||
}
|
||||
rdy = OS_TRUE;
|
||||
} else {
|
||||
pevent2 = ptcb->OSTCBEventPtr;
|
||||
if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
|
||||
if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
|
||||
pevent2->OSEventGrp &= ~ptcb->OSTCBBitY;
|
||||
}
|
||||
}
|
||||
rdy = OS_FALSE; /* No */
|
||||
}
|
||||
ptcb->OSTCBPrio = pip; /* Change owner task prio to PIP */
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3);
|
||||
ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07);
|
||||
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
|
||||
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
|
||||
#else
|
||||
ptcb->OSTCBY = (INT8U)((ptcb->OSTCBPrio >> 4) & 0xFF);
|
||||
ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0F);
|
||||
ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY);
|
||||
ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX);
|
||||
#endif
|
||||
if (rdy == OS_TRUE) { /* If task was ready at owner's priority ...*/
|
||||
OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
|
||||
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
|
||||
} else {
|
||||
pevent2 = ptcb->OSTCBEventPtr;
|
||||
if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */
|
||||
pevent2->OSEventGrp |= ptcb->OSTCBBitY;
|
||||
pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
|
||||
}
|
||||
}
|
||||
OSTCBPrioTbl[pip] = ptcb;
|
||||
}
|
||||
}
|
||||
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
|
||||
OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */
|
||||
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find next highest priority task ready */
|
||||
OS_ENTER_CRITICAL();
|
||||
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
|
||||
case OS_STAT_PEND_OK:
|
||||
*perr = OS_ERR_NONE;
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_ABORT:
|
||||
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_TO:
|
||||
default:
|
||||
OS_EventTaskRemove(OSTCBCur, pevent);
|
||||
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */
|
||||
break;
|
||||
}
|
||||
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
|
||||
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
|
||||
#if (OS_EVENT_MULTI_EN > 0)
|
||||
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
|
||||
#endif
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST TO A MUTUAL EXCLUSION SEMAPHORE
|
||||
*
|
||||
* Description: This function signals a mutual exclusion semaphore
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* mutex.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the mutex was signaled.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
|
||||
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
|
||||
* OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes)
|
||||
* OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX.
|
||||
* OS_ERR_PIP_LOWER If the priority of the new task that owns the Mutex is
|
||||
* HIGHER (i.e. a lower number) than the PIP. This error
|
||||
* indicates that you did not set the PIP higher (lower
|
||||
* number) than ALL the tasks that compete for the Mutex.
|
||||
* Unfortunately, this is something that could not be
|
||||
* detected when the Mutex is created because we don't know
|
||||
* what tasks will be using the Mutex.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
INT8U OSMutexPost (OS_EVENT *pevent)
|
||||
{
|
||||
INT8U pip; /* Priority inheritance priority */
|
||||
INT8U prio;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */
|
||||
}
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pip = (INT8U)(pevent->OSEventCnt >> 8); /* Get priority inheritance priority of mutex */
|
||||
prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's original priority */
|
||||
if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NOT_MUTEX_OWNER);
|
||||
}
|
||||
if (OSTCBCur->OSTCBPrio == pip) { /* Did we have to raise current task's priority? */
|
||||
OSMutex_RdyAtPrio(OSTCBCur, prio); /* Restore the task's original priority */
|
||||
}
|
||||
OSTCBPrioTbl[pip] = OS_TCB_RESERVED; /* Reserve table entry */
|
||||
if (pevent->OSEventGrp != 0) { /* Any task waiting for the mutex? */
|
||||
/* Yes, Make HPT waiting for mutex ready */
|
||||
prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
|
||||
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */
|
||||
pevent->OSEventCnt |= prio;
|
||||
pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */
|
||||
if (prio <= pip) { /* PIP 'must' have a SMALLER prio ... */
|
||||
OS_EXIT_CRITICAL(); /* ... than current task! */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
return (OS_ERR_PIP_LOWER);
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
}
|
||||
pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */
|
||||
pevent->OSEventPtr = (void *)0;
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUERY A MUTUAL EXCLUSION SEMAPHORE
|
||||
*
|
||||
* Description: This function obtains information about a mutex
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired mutex
|
||||
*
|
||||
* p_mutex_data is a pointer to a structure that will contain information about the mutex
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_QUERY_ISR If you called this function from an ISR
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_MUTEX_QUERY_EN > 0
|
||||
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data)
|
||||
{
|
||||
INT8U i;
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
INT8U *psrc;
|
||||
INT8U *pdest;
|
||||
#else
|
||||
INT16U *psrc;
|
||||
INT16U *pdest;
|
||||
#endif
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */
|
||||
}
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */
|
||||
return (OS_ERR_PDATA_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
p_mutex_data->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);
|
||||
p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
|
||||
if (p_mutex_data->OSOwnerPrio == 0xFF) {
|
||||
p_mutex_data->OSValue = OS_TRUE;
|
||||
} else {
|
||||
p_mutex_data->OSValue = OS_FALSE;
|
||||
}
|
||||
p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */
|
||||
psrc = &pevent->OSEventTbl[0];
|
||||
pdest = &p_mutex_data->OSEventTbl[0];
|
||||
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
|
||||
*pdest++ = *psrc++;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif /* OS_MUTEX_QUERY_EN */
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* RESTORE A TASK BACK TO ITS ORIGINAL PRIORITY
|
||||
*
|
||||
* Description: This function makes a task ready at the specified priority
|
||||
*
|
||||
* Arguments : ptcb is a pointer to OS_TCB of the task to make ready
|
||||
*
|
||||
* prio is the desired priority
|
||||
*
|
||||
* Returns : none
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
static void OSMutex_RdyAtPrio (OS_TCB *ptcb, INT8U prio)
|
||||
{
|
||||
INT8U y;
|
||||
|
||||
|
||||
y = ptcb->OSTCBY; /* Remove owner from ready list at 'pip' */
|
||||
OSRdyTbl[y] &= ~ptcb->OSTCBBitX;
|
||||
if (OSRdyTbl[y] == 0) {
|
||||
OSRdyGrp &= ~ptcb->OSTCBBitY;
|
||||
}
|
||||
ptcb->OSTCBPrio = prio;
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
ptcb->OSTCBY = (INT8U)((prio >> (INT8U)3) & (INT8U)0x07);
|
||||
ptcb->OSTCBX = (INT8U) (prio & (INT8U)0x07);
|
||||
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
|
||||
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
|
||||
#else
|
||||
ptcb->OSTCBY = (INT8U)((prio >> (INT8U)4) & (INT8U)0x0F);
|
||||
ptcb->OSTCBX = (INT8U) (prio & (INT8U)0x0F);
|
||||
ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY);
|
||||
ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX);
|
||||
#endif
|
||||
OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready at original priority */
|
||||
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
|
||||
OSTCBPrioTbl[prio] = ptcb;
|
||||
}
|
||||
|
||||
|
||||
#endif /* OS_MUTEX_EN */
|
868
uCOS-II Template/uCOS-II/Source/os_q.c
Normal file
868
uCOS-II Template/uCOS-II/Source/os_q.c
Normal file
@@ -0,0 +1,868 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* MESSAGE QUEUE MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_Q.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ACCEPT MESSAGE FROM QUEUE
|
||||
*
|
||||
* Description: This function checks the queue to see if a message is available. Unlike OSQPend(),
|
||||
* OSQAccept() does not suspend the calling task if a message is not available.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block
|
||||
*
|
||||
* perr 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_EVENT_TYPE You didn't pass a pointer to a queue
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_Q_EMPTY The queue did not contain any messages
|
||||
*
|
||||
* Returns : != (void *)0 is the message in the queue if one is available. The message is removed
|
||||
* from the so the next time OSQAccept() is called, the queue will contain
|
||||
* one less entry.
|
||||
* == (void *)0 if you received a NULL pointer message
|
||||
* if the queue is empty or,
|
||||
* if 'pevent' is a NULL pointer or,
|
||||
* if you passed an invalid event type
|
||||
*
|
||||
* Note(s) : As of V2.60, you can now pass NULL pointers through queues. Because of this, the argument
|
||||
* 'perr' has been added to the API to tell you about the outcome of the call.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_ACCEPT_EN > 0
|
||||
void *OSQAccept (OS_EVENT *pevent, INT8U *perr)
|
||||
{
|
||||
void *pmsg;
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return ((void *)0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return ((void *)0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
|
||||
if (pq->OSQEntries > 0) { /* See if any messages in the queue */
|
||||
pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
|
||||
pq->OSQEntries--; /* Update the number of entries in the queue */
|
||||
if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */
|
||||
pq->OSQOut = pq->OSQStart;
|
||||
}
|
||||
*perr = OS_ERR_NONE;
|
||||
} else {
|
||||
*perr = OS_ERR_Q_EMPTY;
|
||||
pmsg = (void *)0; /* Queue is empty */
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
return (pmsg); /* Return message received (or NULL) */
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* CREATE A MESSAGE QUEUE
|
||||
*
|
||||
* Description: This function creates a message queue if free event control blocks are available.
|
||||
*
|
||||
* Arguments : start is a pointer to the base address of the message queue storage area. The
|
||||
* storage area MUST be declared as an array of pointers to 'void' as follows
|
||||
*
|
||||
* void *MessageStorage[size]
|
||||
*
|
||||
* size is the number of elements in the storage area
|
||||
*
|
||||
* Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the
|
||||
* created queue
|
||||
* == (OS_EVENT *)0 if no event control blocks were available or an error was detected
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_EVENT *OSQCreate (void **start, INT16U size)
|
||||
{
|
||||
OS_EVENT *pevent;
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pevent = OSEventFreeList; /* Get next free event control block */
|
||||
if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
|
||||
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if (pevent != (OS_EVENT *)0) { /* See if we have an event control block */
|
||||
OS_ENTER_CRITICAL();
|
||||
pq = OSQFreeList; /* Get a free queue control block */
|
||||
if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */
|
||||
OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
|
||||
OS_EXIT_CRITICAL();
|
||||
pq->OSQStart = start; /* Initialize the queue */
|
||||
pq->OSQEnd = &start[size];
|
||||
pq->OSQIn = start;
|
||||
pq->OSQOut = start;
|
||||
pq->OSQSize = size;
|
||||
pq->OSQEntries = 0;
|
||||
pevent->OSEventType = OS_EVENT_TYPE_Q;
|
||||
pevent->OSEventCnt = 0;
|
||||
pevent->OSEventPtr = pq;
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
OS_EventWaitListInit(pevent); /* Initalize the wait list */
|
||||
} else {
|
||||
pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */
|
||||
OSEventFreeList = pevent;
|
||||
OS_EXIT_CRITICAL();
|
||||
pevent = (OS_EVENT *)0;
|
||||
}
|
||||
}
|
||||
return (pevent);
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DELETE A MESSAGE QUEUE
|
||||
*
|
||||
* Description: This function deletes a message queue and readies all tasks pending on the queue.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* queue.
|
||||
*
|
||||
* opt determines delete options as follows:
|
||||
* opt == OS_DEL_NO_PEND Delete the queue ONLY if no task pending
|
||||
* opt == OS_DEL_ALWAYS Deletes the queue even if tasks are waiting.
|
||||
* In this case, all the tasks pending will be readied.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
* 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_INVALID_OPT An invalid option was specified
|
||||
* OS_ERR_TASK_WAITING One or more tasks were waiting on the queue
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* Returns : pevent upon error
|
||||
* (OS_EVENT *)0 if the queue was successfully deleted.
|
||||
*
|
||||
* 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) OSQAccept() callers will not know that the intended queue has been deleted unless
|
||||
* they check 'pevent' to see that it's a NULL pointer.
|
||||
* 3) This call can potentially disable interrupts for a long time. The interrupt disable
|
||||
* time is directly proportional to the number of tasks waiting on the queue.
|
||||
* 4) 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.
|
||||
* 5) If the storage for the message queue was allocated dynamically (i.e. using a malloc()
|
||||
* type call) then your application MUST release the memory storage by call the counterpart
|
||||
* call of the dynamic allocation scheme used. If the queue storage was created statically
|
||||
* then, the storage can be reused.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_DEL_EN > 0
|
||||
OS_EVENT *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
BOOLEAN tasks_waiting;
|
||||
OS_EVENT *pevent_return;
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (pevent);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (pevent);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (pevent);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
|
||||
return (pevent);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on queue */
|
||||
tasks_waiting = OS_TRUE; /* Yes */
|
||||
} else {
|
||||
tasks_waiting = OS_FALSE; /* No */
|
||||
}
|
||||
switch (opt) {
|
||||
case OS_DEL_NO_PEND: /* Delete queue only if no task waiting */
|
||||
if (tasks_waiting == OS_FALSE) {
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
|
||||
pq->OSQPtr = OSQFreeList;
|
||||
OSQFreeList = pq;
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Queue has been deleted */
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_TASK_WAITING;
|
||||
pevent_return = pevent;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_DEL_ALWAYS: /* Always delete the queue */
|
||||
while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for queue */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_OK);
|
||||
}
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
|
||||
pq->OSQPtr = OSQFreeList;
|
||||
OSQFreeList = pq;
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
}
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Queue has been deleted */
|
||||
break;
|
||||
|
||||
default:
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_INVALID_OPT;
|
||||
pevent_return = pevent;
|
||||
break;
|
||||
}
|
||||
return (pevent_return);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* FLUSH QUEUE
|
||||
*
|
||||
* Description : This function is used to flush the contents of the message queue.
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Returns : OS_ERR_NONE upon success
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
*
|
||||
* WARNING : 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_Q_FLUSH_EN > 0
|
||||
INT8U OSQFlush (OS_EVENT *pevent)
|
||||
{
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
#endif
|
||||
OS_ENTER_CRITICAL();
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue storage structure */
|
||||
pq->OSQIn = pq->OSQStart;
|
||||
pq->OSQOut = pq->OSQStart;
|
||||
pq->OSQEntries = 0;
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* PEND ON A QUEUE FOR A MESSAGE
|
||||
*
|
||||
* Description: This function waits for a message to be sent to a queue
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired 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.
|
||||
*
|
||||
* perr 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_TIMEOUT A message was not received within the specified 'timeout'.
|
||||
* OS_ERR_PEND_ABORT The wait on the queue was aborted.
|
||||
* OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
|
||||
* would lead to a suspension.
|
||||
* OS_ERR_PEND_LOCKED If you called this function with the scheduler is locked
|
||||
*
|
||||
* 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 'pevent' is a NULL pointer or,
|
||||
* if you didn't pass a pointer to a queue.
|
||||
*
|
||||
* Note(s) : As of V2.60, this function allows you to receive NULL pointer messages.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
|
||||
{
|
||||
void *pmsg;
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return ((void *)0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return ((void *)0);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
|
||||
return ((void *)0);
|
||||
}
|
||||
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
|
||||
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
|
||||
return ((void *)0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
|
||||
if (pq->OSQEntries > 0) { /* See if any messages in the queue */
|
||||
pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
|
||||
pq->OSQEntries--; /* Update the number of entries in the queue */
|
||||
if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */
|
||||
pq->OSQOut = pq->OSQStart;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (pmsg); /* Return message received */
|
||||
}
|
||||
OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
|
||||
OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
|
||||
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find next highest priority task ready to run */
|
||||
OS_ENTER_CRITICAL();
|
||||
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
|
||||
case OS_STAT_PEND_OK: /* Extract message from TCB (Put there by QPost) */
|
||||
pmsg = OSTCBCur->OSTCBMsg;
|
||||
*perr = OS_ERR_NONE;
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_ABORT:
|
||||
pmsg = (void *)0;
|
||||
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_TO:
|
||||
default:
|
||||
OS_EventTaskRemove(OSTCBCur, pevent);
|
||||
pmsg = (void *)0;
|
||||
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
|
||||
break;
|
||||
}
|
||||
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
|
||||
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
|
||||
#if (OS_EVENT_MULTI_EN > 0)
|
||||
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
|
||||
#endif
|
||||
OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (pmsg); /* Return received message */
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* 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(), OSQPostFront() or OSQPostOpt().
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired queue.
|
||||
*
|
||||
* opt determines the type of ABORT performed:
|
||||
* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
|
||||
* queue
|
||||
* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
|
||||
* queue
|
||||
*
|
||||
* perr is a pointer to where an error message will be deposited. Possible error
|
||||
* messages are:
|
||||
*
|
||||
* OS_ERR_NONE No tasks were waiting on the queue.
|
||||
* OS_ERR_PEND_ABORT 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_EVENT_TYPE If you didn't pass a pointer to a queue.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_PEND_ABORT_EN > 0
|
||||
INT8U OSQPendAbort (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
INT8U nbr_tasks;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task waiting on queue? */
|
||||
nbr_tasks = 0;
|
||||
switch (opt) {
|
||||
case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */
|
||||
while (pevent->OSEventGrp != 0) { /* Yes, ready ALL tasks waiting on queue */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_PEND_OPT_NONE:
|
||||
default: /* No, ready HPT waiting on queue */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
break;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find HPT ready to run */
|
||||
*perr = OS_ERR_PEND_ABORT;
|
||||
return (nbr_tasks);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (0); /* No tasks waiting on queue */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST MESSAGE TO A QUEUE
|
||||
*
|
||||
* Description: This function sends a message to a queue
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired queue
|
||||
*
|
||||
* pmsg is a pointer to the message to send.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
*
|
||||
* Note(s) : As of V2.60, this function allows you to send NULL pointer messages.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_POST_EN > 0
|
||||
INT8U OSQPost (OS_EVENT *pevent, void *pmsg)
|
||||
{
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task pending on queue */
|
||||
/* Ready highest priority task waiting on event */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
|
||||
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_Q_FULL);
|
||||
}
|
||||
*pq->OSQIn++ = pmsg; /* Insert message into queue */
|
||||
pq->OSQEntries++; /* Update the nbr of entries in the queue */
|
||||
if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
|
||||
pq->OSQIn = pq->OSQStart;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST MESSAGE TO THE FRONT OF A QUEUE
|
||||
*
|
||||
* Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
|
||||
* the front instead of the end of the queue. Using OSQPostFront() allows you to send
|
||||
* 'priority' messages.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired queue
|
||||
*
|
||||
* pmsg is a pointer to the message to send.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
*
|
||||
* Note(s) : As of V2.60, this function allows you to send NULL pointer messages.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_POST_FRONT_EN > 0
|
||||
INT8U OSQPostFront (OS_EVENT *pevent, void *pmsg)
|
||||
{
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task pending on queue */
|
||||
/* Ready highest priority task waiting on event */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
|
||||
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_Q_FULL);
|
||||
}
|
||||
if (pq->OSQOut == pq->OSQStart) { /* Wrap OUT ptr if we are at the 1st queue entry */
|
||||
pq->OSQOut = pq->OSQEnd;
|
||||
}
|
||||
pq->OSQOut--;
|
||||
*pq->OSQOut = pmsg; /* Insert message into queue */
|
||||
pq->OSQEntries++; /* Update the nbr of entries in the queue */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST MESSAGE TO A QUEUE
|
||||
*
|
||||
* Description: This function sends a message to a queue. This call has been added to reduce code size
|
||||
* since it can replace both OSQPost() and OSQPostFront(). Also, this function adds the
|
||||
* capability to broadcast a message to ALL tasks waiting on the message queue.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired queue
|
||||
*
|
||||
* pmsg is a pointer to the message to send.
|
||||
*
|
||||
* opt determines the type of POST performed:
|
||||
* OS_POST_OPT_NONE POST to a single waiting task
|
||||
* (Identical to OSQPost())
|
||||
* OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the queue
|
||||
* OS_POST_OPT_FRONT POST as LIFO (Simulates OSQPostFront())
|
||||
* OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_Q_FULL If the queue cannot accept any more messages because it is full.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
*
|
||||
* Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the
|
||||
* interrupt disable time is proportional to the number of tasks waiting on the queue.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_POST_OPT_EN > 0
|
||||
INT8U OSQPostOpt (OS_EVENT *pevent, void *pmsg, INT8U opt)
|
||||
{
|
||||
OS_Q *pq;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */
|
||||
if ((opt & OS_POST_OPT_BROADCAST) != 0x00) { /* Do we need to post msg to ALL waiting tasks ? */
|
||||
while (pevent->OSEventGrp != 0) { /* Yes, Post to ALL tasks waiting on queue */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
|
||||
}
|
||||
} else { /* No, Post to HPT waiting on queue */
|
||||
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if ((opt & OS_POST_OPT_NO_SCHED) == 0) { /* See if scheduler needs to be invoked */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
}
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
|
||||
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_Q_FULL);
|
||||
}
|
||||
if ((opt & OS_POST_OPT_FRONT) != 0x00) { /* Do we post to the FRONT of the queue? */
|
||||
if (pq->OSQOut == pq->OSQStart) { /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
|
||||
pq->OSQOut = pq->OSQEnd; /* ... are at the 1st queue entry */
|
||||
}
|
||||
pq->OSQOut--;
|
||||
*pq->OSQOut = pmsg; /* Insert message into queue */
|
||||
} else { /* No, Post as FIFO */
|
||||
*pq->OSQIn++ = pmsg; /* Insert message into queue */
|
||||
if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
|
||||
pq->OSQIn = pq->OSQStart;
|
||||
}
|
||||
}
|
||||
pq->OSQEntries++; /* Update the nbr of entries in the queue */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUERY A MESSAGE QUEUE
|
||||
*
|
||||
* Description: This function obtains information about a message queue.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired queue
|
||||
*
|
||||
* p_q_data is a pointer to a structure that will contain information about the message
|
||||
* queue.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non queue.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
|
||||
* OS_ERR_PDATA_NULL If 'p_q_data' is a NULL pointer
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_Q_QUERY_EN > 0
|
||||
INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *p_q_data)
|
||||
{
|
||||
OS_Q *pq;
|
||||
INT8U i;
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
INT8U *psrc;
|
||||
INT8U *pdest;
|
||||
#else
|
||||
INT16U *psrc;
|
||||
INT16U *pdest;
|
||||
#endif
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (p_q_data == (OS_Q_DATA *)0) { /* Validate 'p_q_data' */
|
||||
return (OS_ERR_PDATA_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
p_q_data->OSEventGrp = pevent->OSEventGrp; /* Copy message queue wait list */
|
||||
psrc = &pevent->OSEventTbl[0];
|
||||
pdest = &p_q_data->OSEventTbl[0];
|
||||
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
|
||||
*pdest++ = *psrc++;
|
||||
}
|
||||
pq = (OS_Q *)pevent->OSEventPtr;
|
||||
if (pq->OSQEntries > 0) {
|
||||
p_q_data->OSMsg = *pq->OSQOut; /* Get next message to return if available */
|
||||
} else {
|
||||
p_q_data->OSMsg = (void *)0;
|
||||
}
|
||||
p_q_data->OSNMsgs = pq->OSQEntries;
|
||||
p_q_data->OSQSize = pq->OSQSize;
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif /* OS_Q_QUERY_EN */
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUEUE MODULE INITIALIZATION
|
||||
*
|
||||
* Description : This function is called by uC/OS-II to initialize the message queue module. Your
|
||||
* application MUST NOT call this function.
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Returns : none
|
||||
*
|
||||
* Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void OS_QInit (void)
|
||||
{
|
||||
#if OS_MAX_QS == 1
|
||||
OSQFreeList = &OSQTbl[0]; /* Only ONE queue! */
|
||||
OSQFreeList->OSQPtr = (OS_Q *)0;
|
||||
#endif
|
||||
|
||||
#if OS_MAX_QS >= 2
|
||||
INT16U i;
|
||||
OS_Q *pq1;
|
||||
OS_Q *pq2;
|
||||
|
||||
|
||||
|
||||
OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl)); /* Clear the queue table */
|
||||
pq1 = &OSQTbl[0];
|
||||
pq2 = &OSQTbl[1];
|
||||
for (i = 0; i < (OS_MAX_QS - 1); i++) { /* Init. list of free QUEUE control blocks */
|
||||
pq1->OSQPtr = pq2;
|
||||
pq1++;
|
||||
pq2++;
|
||||
}
|
||||
pq1->OSQPtr = (OS_Q *)0;
|
||||
OSQFreeList = &OSQTbl[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* OS_Q_EN */
|
609
uCOS-II Template/uCOS-II/Source/os_sem.c
Normal file
609
uCOS-II Template/uCOS-II/Source/os_sem.c
Normal file
@@ -0,0 +1,609 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* SEMAPHORE MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_SEM.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
#if OS_SEM_EN > 0
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* ACCEPT SEMAPHORE
|
||||
*
|
||||
* Description: This function checks the semaphore to see if a resource is available or, if an event
|
||||
* occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
|
||||
* resource is not available or the event did not occur.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block
|
||||
*
|
||||
* Returns : > 0 if the resource is available or the event did not occur the semaphore is
|
||||
* decremented to obtain the resource.
|
||||
* == 0 if the resource is not available or the event did not occur or,
|
||||
* if 'pevent' is a NULL pointer or,
|
||||
* if you didn't pass a pointer to a semaphore
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_SEM_ACCEPT_EN > 0
|
||||
INT16U OSSemAccept (OS_EVENT *pevent)
|
||||
{
|
||||
INT16U cnt;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
return (0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
cnt = pevent->OSEventCnt;
|
||||
if (cnt > 0) { /* See if resource is available */
|
||||
pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
return (cnt); /* Return semaphore count */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* CREATE A SEMAPHORE
|
||||
*
|
||||
* Description: This function creates a semaphore.
|
||||
*
|
||||
* Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is
|
||||
* available (or no event has occurred). You initialize the semaphore to a
|
||||
* non-zero value to specify how many resources are available (e.g. if you have
|
||||
* 10 resources, you would initialize the semaphore to 10).
|
||||
*
|
||||
* Returns : != (void *)0 is a pointer to the event control block (OS_EVENT) associated with the
|
||||
* created semaphore
|
||||
* == (void *)0 if no event control blocks were available
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
OS_EVENT *OSSemCreate (INT16U cnt)
|
||||
{
|
||||
OS_EVENT *pevent;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
pevent = OSEventFreeList; /* Get next free event control block */
|
||||
if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
|
||||
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
if (pevent != (OS_EVENT *)0) { /* Get an event control block */
|
||||
pevent->OSEventType = OS_EVENT_TYPE_SEM;
|
||||
pevent->OSEventCnt = cnt; /* Set semaphore value */
|
||||
pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
|
||||
}
|
||||
return (pevent);
|
||||
}
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DELETE A SEMAPHORE
|
||||
*
|
||||
* Description: This function deletes a semaphore and readies all tasks pending on the semaphore.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* semaphore.
|
||||
*
|
||||
* opt determines delete options as follows:
|
||||
* opt == OS_DEL_NO_PEND Delete semaphore ONLY if no task pending
|
||||
* opt == OS_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
|
||||
* In this case, all the tasks pending will be readied.
|
||||
*
|
||||
* perr is a pointer to an error code that can contain one of the following values:
|
||||
* 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_INVALID_OPT An invalid option was specified
|
||||
* OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* Returns : pevent upon error
|
||||
* (OS_EVENT *)0 if the semaphore was successfully deleted.
|
||||
*
|
||||
* 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) OSSemAccept() callers will not know that the intended semaphore has been deleted unless
|
||||
* they check 'pevent' to see that it's a NULL pointer.
|
||||
* 3) This call can potentially disable interrupts for a long time. The interrupt disable
|
||||
* time is directly proportional to the number of tasks waiting on the semaphore.
|
||||
* 4) 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_SEM_DEL_EN > 0
|
||||
OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
BOOLEAN tasks_waiting;
|
||||
OS_EVENT *pevent_return;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (pevent);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (pevent);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (pevent);
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
|
||||
return (pevent);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on semaphore */
|
||||
tasks_waiting = OS_TRUE; /* Yes */
|
||||
} else {
|
||||
tasks_waiting = OS_FALSE; /* No */
|
||||
}
|
||||
switch (opt) {
|
||||
case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
|
||||
if (tasks_waiting == OS_FALSE) {
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
|
||||
} else {
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_TASK_WAITING;
|
||||
pevent_return = pevent;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_DEL_ALWAYS: /* Always delete the semaphore */
|
||||
while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for semaphore */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
|
||||
}
|
||||
#if OS_EVENT_NAME_SIZE > 1
|
||||
pevent->OSEventName[0] = '?'; /* Unknown name */
|
||||
pevent->OSEventName[1] = OS_ASCII_NUL;
|
||||
#endif
|
||||
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
|
||||
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
|
||||
pevent->OSEventCnt = 0;
|
||||
OSEventFreeList = pevent; /* Get next free event control block */
|
||||
OS_EXIT_CRITICAL();
|
||||
if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
|
||||
OS_Sched(); /* Find highest priority task ready to run */
|
||||
}
|
||||
*perr = OS_ERR_NONE;
|
||||
pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
|
||||
break;
|
||||
|
||||
default:
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_INVALID_OPT;
|
||||
pevent_return = pevent;
|
||||
break;
|
||||
}
|
||||
return (pevent_return);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* PEND ON SEMAPHORE
|
||||
*
|
||||
* Description: This function waits for a semaphore.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* 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 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).
|
||||
*
|
||||
* perr 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 owns the resource
|
||||
* or, the event you are waiting for occurred.
|
||||
* OS_ERR_TIMEOUT The semaphore was not received within the specified
|
||||
* 'timeout'.
|
||||
* OS_ERR_PEND_ABORT The wait on the semaphore was aborted.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
|
||||
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
|
||||
* would lead to a suspension.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
|
||||
*
|
||||
* Returns : none
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
/*$PAGE*/
|
||||
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return;
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return;
|
||||
}
|
||||
if (OSIntNesting > 0) { /* See if called from ISR ... */
|
||||
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
|
||||
return;
|
||||
}
|
||||
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
|
||||
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
|
||||
return;
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */
|
||||
pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
/* Otherwise, must wait until event occurs */
|
||||
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
|
||||
OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
|
||||
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find next highest priority task ready */
|
||||
OS_ENTER_CRITICAL();
|
||||
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
|
||||
case OS_STAT_PEND_OK:
|
||||
*perr = OS_ERR_NONE;
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_ABORT:
|
||||
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
|
||||
break;
|
||||
|
||||
case OS_STAT_PEND_TO:
|
||||
default:
|
||||
OS_EventTaskRemove(OSTCBCur, pevent);
|
||||
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
|
||||
break;
|
||||
}
|
||||
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
|
||||
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
|
||||
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
|
||||
#if (OS_EVENT_MULTI_EN > 0)
|
||||
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
|
||||
#endif
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* 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 : pevent is a pointer to the event control block associated with the desired
|
||||
* semaphore.
|
||||
*
|
||||
* opt determines the type of ABORT performed:
|
||||
* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
|
||||
* semaphore
|
||||
* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
|
||||
* semaphore
|
||||
*
|
||||
* perr is a pointer to where an error message will be deposited. Possible error
|
||||
* messages are:
|
||||
*
|
||||
* OS_ERR_NONE No tasks were waiting on the semaphore.
|
||||
* OS_ERR_PEND_ABORT 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_EVENT_TYPE If you didn't pass a pointer to a semaphore.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_SEM_PEND_ABORT_EN > 0
|
||||
INT8U OSSemPendAbort (OS_EVENT *pevent, INT8U opt, INT8U *perr)
|
||||
{
|
||||
INT8U nbr_tasks;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return (0);
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return (0);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task waiting on semaphore? */
|
||||
nbr_tasks = 0;
|
||||
switch (opt) {
|
||||
case OS_PEND_OPT_BROADCAST: /* Do we need to abort ALL waiting tasks? */
|
||||
while (pevent->OSEventGrp != 0) { /* Yes, ready ALL tasks waiting on semaphore */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
}
|
||||
break;
|
||||
|
||||
case OS_PEND_OPT_NONE:
|
||||
default: /* No, ready HPT waiting on semaphore */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_ABORT);
|
||||
nbr_tasks++;
|
||||
break;
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find HPT ready to run */
|
||||
*perr = OS_ERR_PEND_ABORT;
|
||||
return (nbr_tasks);
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
return (0); /* No tasks waiting on semaphore */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* POST TO A SEMAPHORE
|
||||
*
|
||||
* Description: This function signals a semaphore
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* semaphore.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the semaphore was signaled.
|
||||
* OS_ERR_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
|
||||
* signalled the semaphore more often than you waited on it with either
|
||||
* OSSemAccept() or OSSemPend().
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
INT8U OSSemPost (OS_EVENT *pevent)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
if (pevent->OSEventGrp != 0) { /* See if any task waiting for semaphore */
|
||||
/* Ready HPT waiting on event */
|
||||
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find HPT ready to run */
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
|
||||
pevent->OSEventCnt++; /* Increment semaphore count to register event */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
|
||||
return (OS_ERR_SEM_OVF);
|
||||
}
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* QUERY A SEMAPHORE
|
||||
*
|
||||
* Description: This function obtains information about a semaphore
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block associated with the desired
|
||||
* semaphore
|
||||
*
|
||||
* p_sem_data is a pointer to a structure that will contain information about the
|
||||
* semaphore.
|
||||
*
|
||||
* Returns : OS_ERR_NONE The call was successful and the message was sent
|
||||
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non semaphore.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
* OS_ERR_PDATA_NULL If 'p_sem_data' is a NULL pointer
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_SEM_QUERY_EN > 0
|
||||
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
|
||||
{
|
||||
#if OS_LOWEST_PRIO <= 63
|
||||
INT8U *psrc;
|
||||
INT8U *pdest;
|
||||
#else
|
||||
INT16U *psrc;
|
||||
INT16U *pdest;
|
||||
#endif
|
||||
INT8U i;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
return (OS_ERR_PEVENT_NULL);
|
||||
}
|
||||
if (p_sem_data == (OS_SEM_DATA *)0) { /* Validate 'p_sem_data' */
|
||||
return (OS_ERR_PDATA_NULL);
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
return (OS_ERR_EVENT_TYPE);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
p_sem_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */
|
||||
psrc = &pevent->OSEventTbl[0];
|
||||
pdest = &p_sem_data->OSEventTbl[0];
|
||||
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
|
||||
*pdest++ = *psrc++;
|
||||
}
|
||||
p_sem_data->OSCnt = pevent->OSEventCnt; /* Get semaphore count */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif /* OS_SEM_QUERY_EN */
|
||||
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* SET SEMAPHORE
|
||||
*
|
||||
* Description: This function sets the semaphore count to the value specified as an argument. Typically,
|
||||
* this value would be 0.
|
||||
*
|
||||
* You would typically use this function when a semaphore is used as a signaling mechanism
|
||||
* and, you want to reset the count value.
|
||||
*
|
||||
* Arguments : pevent is a pointer to the event control block
|
||||
*
|
||||
* cnt is the new value for the semaphore count. You would pass 0 to reset the
|
||||
* semaphore count.
|
||||
*
|
||||
* perr is a pointer to an error code returned by the function as follows:
|
||||
*
|
||||
* OS_ERR_NONE The call was successful and the semaphore value was set.
|
||||
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
|
||||
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
|
||||
* OS_ERR_TASK_WAITING If tasks are waiting on the semaphore.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_SEM_SET_EN > 0
|
||||
void OSSemSet (OS_EVENT *pevent, INT16U cnt, INT8U *perr)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (perr == (INT8U *)0) { /* Validate 'perr' */
|
||||
return;
|
||||
}
|
||||
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
|
||||
*perr = OS_ERR_PEVENT_NULL;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
|
||||
*perr = OS_ERR_EVENT_TYPE;
|
||||
return;
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
*perr = OS_ERR_NONE;
|
||||
if (pevent->OSEventCnt > 0) { /* See if semaphore already has a count */
|
||||
pevent->OSEventCnt = cnt; /* Yes, set it to the new value specified. */
|
||||
} else { /* No */
|
||||
if (pevent->OSEventGrp == 0) { /* See if task(s) waiting? */
|
||||
pevent->OSEventCnt = cnt; /* No, OK to set the value */
|
||||
} else {
|
||||
*perr = OS_ERR_TASK_WAITING;
|
||||
}
|
||||
}
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OS_SEM_EN */
|
1095
uCOS-II Template/uCOS-II/Source/os_task.c
Normal file
1095
uCOS-II Template/uCOS-II/Source/os_task.c
Normal file
File diff suppressed because it is too large
Load Diff
268
uCOS-II Template/uCOS-II/Source/os_time.c
Normal file
268
uCOS-II Template/uCOS-II/Source/os_time.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* uC/OS-II
|
||||
* The Real-Time Kernel
|
||||
* TIME MANAGEMENT
|
||||
*
|
||||
* (c) Copyright 1992-2007, Micrium, Weston, FL
|
||||
* All Rights Reserved
|
||||
*
|
||||
* File : OS_TIME.C
|
||||
* By : Jean J. Labrosse
|
||||
* Version : V2.86
|
||||
*
|
||||
* LICENSING TERMS:
|
||||
* ---------------
|
||||
* uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
|
||||
* If you plan on using uC/OS-II in a commercial product you need to contact Micri<72>m to properly license
|
||||
* its use in your product. We provide ALL the source code for your convenience and to help you experience
|
||||
* uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
|
||||
* licensing fee.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef OS_MASTER_FILE
|
||||
#include <ucos_ii.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* DELAY TASK 'n' TICKS (n from 0 to 65535)
|
||||
*
|
||||
* 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 : ticks is the time delay that the task will be suspended in number of clock 'ticks'.
|
||||
* Note that by specifying 0, the task will not be delayed.
|
||||
*
|
||||
* Returns : none
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
void OSTimeDly (INT16U ticks)
|
||||
{
|
||||
INT8U y;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
|
||||
return;
|
||||
}
|
||||
if (ticks > 0) { /* 0 means no delay! */
|
||||
OS_ENTER_CRITICAL();
|
||||
y = OSTCBCur->OSTCBY; /* Delay current task */
|
||||
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
|
||||
if (OSRdyTbl[y] == 0) {
|
||||
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
|
||||
}
|
||||
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* Find next task to run! */
|
||||
}
|
||||
}
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* 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 255)
|
||||
* minutes specifies the number of minutes (max. 59)
|
||||
* seconds specifies the number of seconds (max. 59)
|
||||
* milli specifies the number of milliseconds (max. 999)
|
||||
*
|
||||
* Returns : OS_ERR_NONE
|
||||
* OS_ERR_TIME_INVALID_MINUTES
|
||||
* OS_ERR_TIME_INVALID_SECONDS
|
||||
* OS_ERR_TIME_INVALID_MS
|
||||
* OS_ERR_TIME_ZERO_DLY
|
||||
* OS_ERR_TIME_DLY_ISR
|
||||
*
|
||||
* Note(s) : 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.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_TIME_DLY_HMSM_EN > 0
|
||||
INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U ms)
|
||||
{
|
||||
INT32U ticks;
|
||||
INT16U loops;
|
||||
|
||||
|
||||
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
|
||||
return (OS_ERR_TIME_DLY_ISR);
|
||||
}
|
||||
#if OS_ARG_CHK_EN > 0
|
||||
if (hours == 0) {
|
||||
if (minutes == 0) {
|
||||
if (seconds == 0) {
|
||||
if (ms == 0) {
|
||||
return (OS_ERR_TIME_ZERO_DLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minutes > 59) {
|
||||
return (OS_ERR_TIME_INVALID_MINUTES); /* Validate arguments to be within range */
|
||||
}
|
||||
if (seconds > 59) {
|
||||
return (OS_ERR_TIME_INVALID_SECONDS);
|
||||
}
|
||||
if (ms > 999) {
|
||||
return (OS_ERR_TIME_INVALID_MS);
|
||||
}
|
||||
#endif
|
||||
/* Compute the total number of clock ticks required.. */
|
||||
/* .. (rounded to the nearest tick) */
|
||||
ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC
|
||||
+ OS_TICKS_PER_SEC * ((INT32U)ms + 500L / OS_TICKS_PER_SEC) / 1000L;
|
||||
loops = (INT16U)(ticks >> 16); /* Compute the integral number of 65536 tick delays */
|
||||
ticks = ticks & 0xFFFFL; /* Obtain the fractional number of ticks */
|
||||
OSTimeDly((INT16U)ticks);
|
||||
while (loops > 0) {
|
||||
OSTimeDly((INT16U)32768u);
|
||||
OSTimeDly((INT16U)32768u);
|
||||
loops--;
|
||||
}
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* 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 can call this function to resume a
|
||||
* task that is waiting for an event with timeout. This would make the task look
|
||||
* like a timeout occurred.
|
||||
*
|
||||
* Also, you cannot resume a task that has called OSTimeDlyHMSM() with a combined time that
|
||||
* exceeds 65535 clock ticks. In other words, if the clock tick runs at 100 Hz then, you will
|
||||
* not be able to resume a delayed task that called OSTimeDlyHMSM(0, 10, 55, 350) or higher:
|
||||
*
|
||||
* (10 Minutes * 60 + 55 Seconds + 0.35) * 100 ticks/second.
|
||||
*
|
||||
* Arguments : prio specifies the priority of the task to resume
|
||||
*
|
||||
* Returns : OS_ERR_NONE Task has been resumed
|
||||
* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed
|
||||
* (i.e. >= OS_LOWEST_PRIO)
|
||||
* OS_ERR_TIME_NOT_DLY Task is not waiting for time to expire
|
||||
* OS_ERR_TASK_NOT_EXIST The desired task has not been created or has been assigned to a Mutex.
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_TIME_DLY_RESUME_EN > 0
|
||||
INT8U OSTimeDlyResume (INT8U prio)
|
||||
{
|
||||
OS_TCB *ptcb;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (prio >= OS_LOWEST_PRIO) {
|
||||
return (OS_ERR_PRIO_INVALID);
|
||||
}
|
||||
OS_ENTER_CRITICAL();
|
||||
ptcb = OSTCBPrioTbl[prio]; /* Make sure that task exist */
|
||||
if (ptcb == (OS_TCB *)0) {
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
|
||||
}
|
||||
if (ptcb == OS_TCB_RESERVED) {
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
|
||||
}
|
||||
if (ptcb->OSTCBDly == 0) { /* See if task is delayed */
|
||||
OS_EXIT_CRITICAL();
|
||||
return (OS_ERR_TIME_NOT_DLY); /* Indicate that task was not delayed */
|
||||
}
|
||||
|
||||
ptcb->OSTCBDly = 0; /* Clear the time delay */
|
||||
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
|
||||
ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY; /* Yes, Clear status flag */
|
||||
ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */
|
||||
} else {
|
||||
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
|
||||
}
|
||||
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
|
||||
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
|
||||
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
|
||||
OS_EXIT_CRITICAL();
|
||||
OS_Sched(); /* See if this is new highest priority */
|
||||
} else {
|
||||
OS_EXIT_CRITICAL(); /* Task may be suspended */
|
||||
}
|
||||
return (OS_ERR_NONE);
|
||||
}
|
||||
#endif
|
||||
/*$PAGE*/
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* GET CURRENT SYSTEM TIME
|
||||
*
|
||||
* Description: This function is used by your application to obtain the current value of the 32-bit
|
||||
* counter which keeps track of the number of clock ticks.
|
||||
*
|
||||
* Arguments : none
|
||||
*
|
||||
* Returns : The current value of OSTime
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_TIME_GET_SET_EN > 0
|
||||
INT32U OSTimeGet (void)
|
||||
{
|
||||
INT32U ticks;
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OS_ENTER_CRITICAL();
|
||||
ticks = OSTime;
|
||||
OS_EXIT_CRITICAL();
|
||||
return (ticks);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* SET SYSTEM CLOCK
|
||||
*
|
||||
* Description: This function sets the 32-bit counter which keeps track of the number of clock ticks.
|
||||
*
|
||||
* Arguments : ticks specifies the new value that OSTime needs to take.
|
||||
*
|
||||
* Returns : none
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
|
||||
#if OS_TIME_GET_SET_EN > 0
|
||||
void OSTimeSet (INT32U ticks)
|
||||
{
|
||||
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
|
||||
OS_CPU_SR cpu_sr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OS_ENTER_CRITICAL();
|
||||
OSTime = ticks;
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
1116
uCOS-II Template/uCOS-II/Source/os_tmr.c
Normal file
1116
uCOS-II Template/uCOS-II/Source/os_tmr.c
Normal file
File diff suppressed because it is too large
Load Diff
1930
uCOS-II Template/uCOS-II/Source/ucos_ii.h
Normal file
1930
uCOS-II Template/uCOS-II/Source/ucos_ii.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user