Example #1
0
/*!
	Remove a task from the scheduler list.  Before attempting to remove the
	task, the owner should ensure that all connections of this task to other
	objects (plumber, semaphore, etc.) are removed PRIOR to calling this
	function, otherwise system corruption will likely occur.
	\fn BOOL Task_Remove(TASK_STRUCT *pstTask_)
	\sa Task_Add()
	\param pstTask_ - pointer to the task structure to remove
	\return (BOOL) TRUE on success, FAIL on failure
*/
BOOL Task_Remove(TASK_STRUCT *pstTask_)
{	
	TASK_STRUCT *pstPrev;
	TASK_STRUCT *pstTarget;
	
	CS_ENTER();
	
	// initialize the target
	pstPrev = pstTask_;
	pstTarget = pstTask_->pstNext;
	
	// Look through the circular list of tasks and find the connectors.
	while (pstTarget != pstTask_)
	{
		// iterate through...
		pstPrev = pstTarget;
		pstTarget = pstTarget->pstNext;
	}
	// Remove the target from the circularly linked list
	pstPrev->pstNext = pstTask_->pstNext;
	
	// De-initialize the "next" pointer in the task list.
	pstTask_->pstNext = NULL;
	
	// Set the task as uninitialized (require initialization before reuse)
	pstTask_->eState = TASK_UNINIT;
	
	CS_EXIT();
	
	// Call a context switch.
	Task_YieldSWI();
	
	// Will not return if the thread deletes itself.	
	return FALSE;
}
Example #2
0
/*!
	Post (release) a semaphore.  If there are other tasks waiting for this 
	semaphore, the highest-priority task in the semaphore wait list will claim
	the semaphore and run.
	\fn BOOL Semaphore_Post(SEMAPHORE_STRUCT *pstSem_)
	\param pstSem_ - pointer to the semaphore to post
*/
void Semaphore_Post(SEMAPHORE_STRUCT *pstSem_)
{	
	BOOL bTaskWait = FALSE;
	
	//!! Disable scheduler + interrupts (callable from ISR)
	CS_ENTER();
	// Nothing is pending
	if (pstSem_->pstTask == NULL)
	{
		// Re-initialize the semaphore
		if (pstSem_->usSem < pstSem_->usMax)
		{
			pstSem_->usSem++;
		}
	}
	else
	{
		// Wake the highest priority task pending on the semaphore
		Semaphore_WakeNextPending(pstSem_);
		bTaskWait = TRUE;
	}	
	CS_EXIT();
	
	if (bTaskWait)
	{
		Task_YieldSWI();
	}
}
Example #3
0
/*!
	Add a task to the scheduler list
	\fn BOOL Task_Add(TASK_STRUCT *pstTask_)
	\sa Task_Remove()
	\param pstTask_ - pointer to the task structure to add
	\return (BOOL) TRUE on success, FAIL on failure
*/
BOOL Task_Add(TASK_STRUCT *pstTask_)
{
	CS_ENTER();
	
	// init the task state
	pstTask_->eState = TASK_READY;
		
	// If the list is empty...
	if (pstCurrentTask == NULL)
	{
		// Circularly linked list...
		pstCurrentTask = pstTask_;
		pstCurrentTask->pstNext = pstCurrentTask;
	}
	// The list isn't empty, insert it somewhere.
	else 
	{
		// reconnect the links...
		pstTask_->pstNext = pstCurrentTask->pstNext;
		pstCurrentTask->pstNext = pstTask_;
	}
	
	CS_EXIT();
	
	// It's all good - no maximum items in the list...
	return TRUE;
}
Example #4
0
/*!
	Signal a task to wait for a semaphore.  If the semaphore is not available,
	the task will block and wait until the semaphore becomes available.
	\fn BOOL Semaphore_Pend(SEMAPHORE_STRUCT *pstSem_, USHORT usTime_)
	\param pstSem_ - pointer to the semaphore to pend on
	\param usTime_ - the time limit to wait for the semaphore. Integer number of ticks or TIME_FOREVER
	\return BOOL - TRUE on success, FALSE on timeout
*/
BOOL Semaphore_Pend(SEMAPHORE_STRUCT *pstSem_,  USHORT usTime_)
{
	BOOL bTaskWait = FALSE;
	BOOL bReturn = TRUE;
	TASK_STRUCT *pstTask;
	//!! Disable Scheduler !!
	CS_ENTER();
	pstTask = Task_GetCurrentTask();
	if (pstSem_->usSem != 0)
	{
		// Semaphore isn't claimed, claim it.
		pstSem_->usSem--;
	}
	else
	{	
		// Remove the task from the ready state - blocking on semaphore
		pstTask->eState = TASK_BLOCKED;
		pstTask->usTimeLeft = usTime_;

		// Add the task to the semaphore's waiting list.
		Semaphore_AddToList(pstSem_, pstTask);
	
		bTaskWait = TRUE;
	}
	CS_EXIT();
	
	if (bTaskWait)
	{
		// Switch tasks immediately
		Task_YieldSWI();
	
		CS_ENTER();
		if (pstTask->bTimeout)
		{
			// If there was a timeout waiting for the semaphore
			bReturn = FALSE;
			Semaphore_DeleteFromList(pstSem_, pstTask);
			pstTask->bTimeout = FALSE;	// Reset the task timeout flag				
		}
		CS_EXIT();
	}
	
	return bReturn;
}
Example #5
0
/*!
	Disables the scheduler, and returns the scheduler's previous state.  This
	is used in combination with Task_SchedulerRestore() to provide the 
	scheduler-disabled context.

	\fn Task_SchedulerDisable(void)
	\return BOOL - the previous state of the scheduler (TRUE = ENABLED)
*/
BOOL Task_SchedulerDisable(void)
{
	BOOL bReturn;
	
	CS_ENTER();
	bReturn = Task_IsSchedulerEnabled();
	Task_SetScheduler(FALSE);
	CS_EXIT();
	
	return bReturn;
}
Example #6
0
/*!
	Set a task to sleep for a period of time specified in the arguments
	\sa Task_Tick()
	\fn void Task_Sleep(USHORT usTime_)
	\param usTime_ - the time period in RTOS ticks to sleep through
*/
void Task_Sleep(USHORT usTime_)
{
	// Do this in a scheduler-disabled context
	CS_ENTER();
		
	pstCurrentTask->eState = TASK_SLEEP;
	pstCurrentTask->usTimeLeft = usTime_;
	
	CS_EXIT();
		
	// Call the scheduler immediately.
	Task_YieldSWI();
}
Example #7
0
//---------------------------------------------------------------------------
void Notify_Wait( Notify_t *pstNotify_, bool *pbFlag_ )
{
    CS_ENTER();
    BlockingObject_Block( (ThreadList_t*)pstNotify_, Scheduler_GetCurrentThread() );
    if (pbFlag_)
    {
        *pbFlag_ = false;
    }
    CS_EXIT();

    Thread_Yield();
    if (pbFlag_)
    {
        *pbFlag_ = true;
    }
}
Example #8
0
//---------------------------------------------------------------------------
K_USHORT ATMegaUART_Read( ATMegaUART_t *pstUART_, K_USHORT usSizeIn_, K_UCHAR *pvData_ )
{
    // Read a string of characters of length N.  Return the number of bytes
    // actually read.  If less than the 1 length, this indicates that
    // the buffer is full and that the app needs to wait.
    
    K_USHORT i = 0;
    K_USHORT usRead = 0;
    K_BOOL bExit = 0;
    K_UCHAR *pucData = (K_UCHAR*)pvData_;
    
    for (i = 0; i < usSizeIn_; i++)
    {        
        // If Tail != Head, there's data in the buffer.
        CS_ENTER();
        if (pstUART_->ucRxTail != pstUART_->ucRxHead)
        {
            // We have room to add the byte, so add it.
            pucData[i] = pstUART_->pucRxBuffer[pstUART_->ucRxTail];
            
            // Update the buffer head pointer.
            pstUART_->ucRxTail++;
            if (pstUART_->ucRxTail >= pstUART_->ucRxSize)
            {
                pstUART_->ucRxTail = 0;
            }
            usRead++;
        }
        else
        {
            // Can't do anything else - the buffer is empty
            bExit = 1; 
        } 
        CS_EXIT();
        
        // If we have to bail because the buffer is empty, do it now.
        if (bExit == 1)
        {
            break;
        }        
    }
    return usRead;
}
Example #9
0
//---------------------------------------------------------------------------
void ATMegaUART_StartTx( ATMegaUART_t *pstUART_ )
{
    // Send the tail byte out.
    K_UCHAR ucNext;

    CS_ENTER();
    
    // Send the byte at the tail index
    UART_UDR = pstUART_->pucTxBuffer[pstUART_->ucTxTail];
    
    // Update the tail index
    ucNext = (pstUART_->ucTxTail + 1);
    if (ucNext >= pstUART_->ucTxSize)
    {
        ucNext = 0;
    }
    pstUART_->ucTxTail = ucNext;
    
    CS_EXIT();
}
Example #10
0
bool Notify_Wait( Notify_t *pstNotify_, K_ULONG ulWaitTimeMS_, bool *pbFlag_ )
{
    bool bUseTimer = false;
    Timer_t stNotifyTimer;

    CS_ENTER();
    if (ulWaitTimeMS_)
    {
        bUseTimer = true;
        Thread_SetExpired( Scheduler_GetCurrentThread(), false );

        Timer_Init( &stNotifyTimer );
        Timer_Start( &stNotifyTimer, 0, ulWaitTimeMS_, TimedNotify_Callback, (void*)pstNotify_);
    }

    Block(g_pstCurrent);

    if (pbFlag_)
    {
        *pbFlag_ = false;
    }
    CS_EXIT();

    Thread_Yield();

    if (pbFlag_)
    {
        *pbFlag_ = true;
    }

    if (bUseTimer)
    {
        Timer_Stop( &stNotifyTimer );
        return ( Thread_GetExpired( Scheduler_GetCurrentThread() ) == false );
    }

    return true;
}
Example #11
0
/*!
	Allocates a single block of memory from the heap based on the required 
	size (if one is available).
	\fn UCHAR *Heap_Alloc(USHORT usSize_)
	\param usSize_ - the size of the block to allocate
	\return pointer to the block of newly-allocated memory, or NULL on failure
*/
UCHAR *Heap_Alloc(USHORT usSize_)
{
	USHORT i;
	BOOL bDone = FALSE;
	UCHAR *pucReturn = NULL;
	
	// Try to allocate the smallest possible block
	for(i = 0; i < HEAP_NUM_ELEMENTS; i++)
	{
		if (stHeap.astHeapElements[i].usSize > usSize_)
		{
			CS_ENTER();
			if (stHeap.astHeapElements[i].bInUse == FALSE)
			{
				// Found smallest suitable block that isn't in use.
				
				// Set the in-use flag to true
				stHeap.astHeapElements[i].bInUse = TRUE;
				// Set the return value
				pucReturn = &(stHeap.aucPool[stHeap.astHeapElements[i].usOffset]);
				// Found something, bail.
				bDone = TRUE;
			}
			CS_EXIT();

			// break on success.
			if (bDone)
			{
				break;
			}
		}
	}
	
	// Return the address of the 
	return pucReturn;
}
Example #12
0
/*!
	De-allocates a previously allocated block of memory based on the address
	given.
	\fn void Heap_Free(void *pvData_)
	\param pvData_ - pointer to the previously-allocated memory block
*/
void Heap_Free(void *pvData_)
{
	USHORT i;
	BOOL bDone = FALSE;
	UCHAR *pucData = NULL;
	UCHAR *pucTemp = NULL;
	
	// Set the UCHAR* version of the input void parameter
	pucData = (UCHAR*)pvData_;
	
	// Go through the whole list trying to find the matching element allocated
	for (i = 0; i < HEAP_NUM_ELEMENTS; i++)
	{
		// Only looking at allocated elements
		if (stHeap.astHeapElements[i].bInUse == TRUE)
		{
			CS_ENTER();
			// Get the address for the element's array
			pucTemp = &(stHeap.aucPool[stHeap.astHeapElements[i].usOffset]);
			// Element addresses match, this is the match
			if (pucTemp == pucData)
			{
				// Deallocate the element and exit
				stHeap.astHeapElements[i].bInUse = FALSE;
				bDone = TRUE;
			}
			CS_EXIT();
			
			// Break on success
			if (bDone)
			{
				break;
			}
		}
	}
}
Example #13
0
//---------------------------------------------------------------------------
void Notify_Signal( Notify_t *pstNotify_ )
{
    bool bReschedule = false;

    CS_ENTER();
    Thread_t *pstCurrent = (Thread_t*)LinkList_GetHead((LinkListNode_t*)pstNotify_);
    while (pstCurrent != NULL)
    {
        BlockingObject_UnBlock( pstCurrent );
        if ( !bReschedule &&
           ( Thread_GetCurPriority( pstCurrent ) >=
             Thread_GetCurPriority( Scheduler_GetCurrentThread() ) ) )
        {
            bReschedule = true;
        }
        pstCurrent = (Thread_t*)LinkList_GetHead(pstNotify_);
    }
    CS_EXIT();

    if (bReschedule)
    {
        Thread_Yield();
    }
}
Example #14
0
//---------------------------------------------------------------------------
K_USHORT ATMegaUART_Write( ATMegaUART_t *pstUART_, K_USHORT usSizeOut_, K_UCHAR *pvData_)
{
    // Write a string of characters of length N.  Return the number of bytes
    // actually written.  If less than the 1 length, this indicates that
    // the buffer is full and that the app needs to wait.    
    K_USHORT i = 0;
    K_USHORT usWritten = 0;
    K_UCHAR ucNext;
    K_BOOL bActivate = 0;
    K_BOOL bExit = 0;
    K_UCHAR *pucData = (K_UCHAR*)pvData_;
    
    // If the head = tail, we need to start sending data out the data ourselves.
    if (pstUART_->ucTxHead == pstUART_->ucTxTail)
    {
        bActivate = 1;
    }
    
    for (i = 0; i < usSizeOut_; i++)
    {
        CS_ENTER();
        // Check that head != tail (we have room)
        ucNext = (pstUART_->ucTxHead + 1);
        if (ucNext >= pstUART_->ucTxSize)
        {
            ucNext = 0;
        }
        
        if (ucNext != pstUART_->ucTxTail)
        {
            // We have room to add the byte, so add it.
            pstUART_->pucTxBuffer[pstUART_->ucTxHead] = pucData[i];
            
            // Update the buffer head pointer.
            pstUART_->ucTxHead = ucNext;
            usWritten++;
        }
        else
        {
            // Can't do anything - buffer is full
            bExit = 1;
        } 
        CS_EXIT();
        
        // bail if the buffer is full
        if (bExit == 1)
        {
            break;
        }        
    }
    
    // Activate the transmission if we're currently idle
    if (bActivate == 1)
    {
        // We know we're idle if we get here.
        CS_ENTER();
        if (UART_SRA & (1 << UDRE0))
        {
            ATMegaUART_StartTx(pstUART_);
        }        
        CS_EXIT();
    }
    
     return usWritten;
}
Example #15
0
/*!
	Used to restore the state of the scheduler after performing an operation
	that operates in a scheduler-disabled context

	\fn Task_SchedulerRestore(BOOL bState_)
	\param bState_ - TRUE to enable the scheduler, FALSE to disable the scheduler
*/
void Task_SchedulerRestore(BOOL bState_)
{
	CS_ENTER();
	Task_SetScheduler(bState_);
	CS_EXIT();
}