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:
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