/******************************************************************************
* Nano-RK, a real-time operating system for sensor networks.
* Copyright (C) 2007, Real-Time and Multimedia Lab, Carnegie Mellon University
* All rights reserved.
*
* This is the Open Source Version of Nano-RK included as part of a Dual
* Licensing Model. If you are unsure which license to use please refer to:
* http://www.nanork.org/nano-RK/wiki/Licensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Contributing Authors (specific to this file):
* Anthony Rowe
* Zane Starr
* Anand Eswaren
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
//#define TIME_PAD 2
inline void _nrk_wait_for_scheduler ();
uint8_t nrk_get_high_ready_task_ID ()
{
return (_head_node->task_ID);
}
void nrk_print_readyQ ()
{
nrk_queue *ptr;
ptr = _head_node;
//nrk_kprintf (PSTR ("nrk_queue: "));
while (ptr != NULL) {
//printf ("%d ", ptr->task_ID);
ptr = ptr->Next;
}
//nrk_kprintf (PSTR ("\n\r"));
}
void nrk_add_to_readyQ (int8_t task_ID)
{
nrk_queue *NextNode;
nrk_queue *CurNode;
//printf( "nrk_add_to_readyQ %d\n",task_ID );
// nrk_queue full
if (_free_node == NULL) {
return;
}
NextNode = _head_node;
CurNode = _free_node;
if (_head_node != NULL) {
while (NextNode != NULL) {
if (nrk_task_TCB[NextNode->task_ID].elevated_prio_flag)
if (nrk_task_TCB[NextNode->task_ID].task_prio_ceil <
nrk_task_TCB[task_ID].task_prio)
break;
if (nrk_task_TCB[task_ID].elevated_prio_flag)
if (nrk_task_TCB[NextNode->task_ID].task_prio <
nrk_task_TCB[task_ID].task_prio_ceil)
break;
if (nrk_task_TCB[NextNode->task_ID].task_prio <
nrk_task_TCB[task_ID].task_prio)
break;
NextNode = NextNode->Next;
}
// while ((NextNode != NULL) && ((nrk_task_TCB[NextNode->task_ID].task_prio >= nrk_task_TCB[task_ID].task_prio)|| ) {
// NextNode = NextNode->Next;}
// Stop if nextNode is freenode or next node less prio or (equal and elevated
// Issues - 1 comes, becomes 2', 1 more comes (2' 1) then 2 comes where should it be placed ?
// 2' 2 1 or 2 2' 1 in ready q , what happens after 2'->1, what if 2'->2
}
CurNode->task_ID = task_ID;
_free_node = _free_node->Next;
if (NextNode == _head_node) {
//at start
if (_head_node != NULL) {
CurNode->Next = _head_node;
CurNode->Prev = NULL;
_head_node->Prev = CurNode;
}
else {
CurNode->Next = NULL;
CurNode->Prev = NULL;
_free_node->Prev = CurNode;
}
_head_node = CurNode;
}
else {
if (NextNode != _free_node) {
// Insert in middle
CurNode->Prev = NextNode->Prev;
CurNode->Next = NextNode;
(NextNode->Prev)->Next = CurNode;
NextNode->Prev = CurNode;
}
else {
//insert at end
CurNode->Next = NULL;
CurNode->Prev = _free_node->Prev;
_free_node->Prev = CurNode;
}
}
}
void nrk_rem_from_readyQ (int8_t task_ID)
{
nrk_queue *CurNode;
// nrk_queue *tempNode;
//return;
/*CurNode = _head_node;
_head_node = _head_node->Next;
_head_node->Prev = NULL;
if (_free_node == NULL)
{
tempNode = _head_node;
while (tempNode->Next!=NULL) tempNode=tempNode->Next;
CurNode->Next = NULL;
CurNode->Prev = tempNode;
tempNode->Next = CurNode;
_free_node = CurNode;
}
else
{
CurNode->Next = _free_node;
_free_node->Prev = CurNode;
_free_node = CurNode;
}
*/
// printf("nrk_rem_from_readyQ_nrk_queue %d\n",task_ID);
if (_head_node == NULL)
return;
CurNode = _head_node;
if (_head_node->task_ID == task_ID) {
//REmove from start
_head_node = _head_node->Next;
_head_node->Prev = NULL;
}
else {
while ((CurNode != NULL) && (CurNode->task_ID != task_ID))
CurNode = CurNode->Next;
if (CurNode == NULL)
return;
(CurNode->Prev)->Next = CurNode->Next; //Both for middle and end
if (CurNode->Next != NULL)
(CurNode->Next)->Prev = CurNode->Prev; // Only for middle
}
// Add to free list
if (_free_node == NULL) {
_free_node = CurNode;
_free_node->Next = NULL;
}
else {
CurNode->Next = _free_node;
_free_node->Prev = CurNode;
_free_node = CurNode;
}
_free_node->Prev = NULL;
}
nrk_status_t nrk_activate_task (nrk_task_type * Task)
{
uint8_t rtype;
void *topOfStackPtr;
topOfStackPtr =
(void *) nrk_task_stk_init (Task->task, Task->Ptos, Task->Pbos);
//printf("activate %d\n",(int)Task.task_ID);
if (Task->FirstActivation == TRUE) {
rtype = nrk_TCB_init (Task, topOfStackPtr, Task->Pbos, 0, (void *) 0, 0);
Task->FirstActivation = FALSE;
}
else {
if (nrk_task_TCB[Task->task_ID].task_state != SUSPENDED)
return NRK_ERROR;
//Re-init some parts of TCB
nrk_task_TCB[Task->task_ID].OSTaskStkPtr = (NRK_STK *) topOfStackPtr;
}
//nrk_task_TCB[Task->task_ID].task_state = READY;
// Remove from suspended or waiting if extended
// OSSchedLock();
// If Idle Task then Add to ready Q
//if(Task->task_ID==0) nrk_add_to_readyQ(Task->task_ID);
//nrk_add_to_readyQ(Task->task_ID);
//printf( "task %d nw %d \r\n",Task->task_ID,nrk_task_TCB[Task->task_ID].next_wakeup);
//printf( "task %d nw %d \r\n",Task->task_ID,Task->offset.secs);
if (nrk_task_TCB[Task->task_ID].next_wakeup == 0) {
nrk_task_TCB[Task->task_ID].task_state = READY;
nrk_add_to_readyQ (Task->task_ID);
}
return NRK_OK;
}
nrk_status_t nrk_terminate_task ()
{
nrk_rem_from_readyQ (nrk_cur_task_TCB->task_ID);
nrk_cur_task_TCB->task_state = FINISHED;
// HAHA, there is NO next period...
nrk_wait_until_next_period ();
return NRK_OK;
}
int8_t nrk_wait_until_next_period ()
{
uint8_t timer;
nrk_stack_check ();
// Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable
nrk_int_disable ();
nrk_cur_task_TCB->num_periods = 1;
nrk_cur_task_TCB->suspend_flag = 1;
timer = _nrk_os_timer_get ();
//nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1;
if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD))
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
nrk_int_enable ();
_nrk_wait_for_scheduler ();
return NRK_OK;
}
int8_t nrk_wait_until_next_n_periods (uint16_t p)
{
uint8_t timer;
nrk_stack_check ();
if (p == 0)
p = 1;
// Next Period Wakeup Time is Set inside scheduler when a task becomes Runnable
nrk_int_disable ();
nrk_cur_task_TCB->suspend_flag = 1;
nrk_cur_task_TCB->num_periods = p;
timer = _nrk_os_timer_get ();
//nrk_cur_task_TCB->cpu_remaining=_nrk_prev_timer_val+1;
// +2 allows for potential time conflict resolution
if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD)) // 254 8bit overflow point - 2
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
nrk_int_enable ();
_nrk_wait_for_scheduler ();
return NRK_OK;
}
/*
* nrk_wait_ticks()
*
* This function will wait until a specified number of
* timer ticks starting from when the task was swapped in.
* This means that this function can set periodic timing
* taking into account any task processing time.
*
*/
int8_t nrk_wait_ticks (uint16_t ticks)
{
uint8_t timer;
nrk_int_disable ();
nrk_cur_task_TCB->suspend_flag = 1;
timer = _nrk_os_timer_get ();
nrk_cur_task_TCB->next_wakeup = ticks + timer;
if (timer < MAX_SCHED_WAKEUP_TIME - TIME_PAD)
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
//else nrk_cur_task_TCB->next_wakeup=ticks+1;
nrk_int_enable ();
//while(nrk_cur_task_TCB->suspend_flag==1);
_nrk_wait_for_scheduler ();
return NRK_OK;
}
/*
* nrk_wait_until_ticks()
*
* This function will wait until a specified number of
* timer ticks starting from when the task was swapped in.
* This means that this function can set periodic timing
* taking into account any task processing time.
*
*/
int8_t nrk_wait_until_ticks (uint16_t ticks)
{
uint8_t timer;
nrk_int_disable ();
nrk_cur_task_TCB->suspend_flag = 1;
nrk_cur_task_TCB->next_wakeup = ticks;
timer = _nrk_os_timer_get ();
if (timer < MAX_SCHED_WAKEUP_TIME - TIME_PAD)
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
//else nrk_cur_task_TCB->next_wakeup=ticks+1;
nrk_int_enable ();
//while(nrk_cur_task_TCB->suspend_flag==1);
_nrk_wait_for_scheduler ();
return NRK_OK;
}
int8_t nrk_set_next_wakeup (nrk_time_t t)
{
uint8_t timer;
uint16_t nw;
nrk_int_disable ();
timer = _nrk_os_timer_get ();
nw = _nrk_time_to_ticks (t);
if (nw <= TIME_PAD)
return NRK_ERROR;
nrk_cur_task_TCB->next_wakeup = nw + timer;
/* if(timer<(254-TIME_PAD))
if((timer+TIME_PAD)<=_nrk_get_next_wakeup())
{
timer+=TIME_PAD;
_nrk_prev_timer_val=timer;
_nrk_set_next_wakeup(timer);
}
*/
// nrk_cur_task_TCB->nw_flag=1;
nrk_int_enable ();
return NRK_OK;
}
/*
* nrk_wait_until_nw()
*
* This function will wait until a specified number of
* timer ticks starting from when the task was swapped in.
* This means that this function can set periodic timing
* taking into account any task processing time.
*
*/
int8_t nrk_wait_until_nw ()
{
uint8_t timer;
nrk_int_disable ();
nrk_cur_task_TCB->suspend_flag = 1;
nrk_cur_task_TCB->nw_flag = 1;
timer = _nrk_os_timer_get ();
if (timer < MAX_SCHED_WAKEUP_TIME - TIME_PAD)
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
//else nrk_cur_task_TCB->next_wakeup=ticks+1;
nrk_int_enable ();
//while(nrk_cur_task_TCB->suspend_flag==1);
_nrk_wait_for_scheduler ();
return NRK_OK;
}
int8_t nrk_wait (nrk_time_t t)
{
uint8_t timer;
uint16_t nw;
nrk_stack_check ();
nrk_int_disable ();
nrk_cur_task_TCB->suspend_flag = 1;
nrk_cur_task_TCB->num_periods = 1;
timer = _nrk_os_timer_get ();
//printf( "t1 %lu %lu\n",t.secs, t.nano_secs/NANOS_PER_MS);
nw = _nrk_time_to_ticks (t);
//printf( "t2 %u\n",nw );
nrk_cur_task_TCB->next_wakeup = nw + timer;
//printf( "wu %u\n",nrk_cur_task_TCB->next_wakeup );
if (timer < (MAX_SCHED_WAKEUP_TIME - TIME_PAD))
if ((timer + TIME_PAD) <= _nrk_get_next_wakeup ()) {
timer += TIME_PAD;
_nrk_prev_timer_val = timer;
_nrk_set_next_wakeup (timer);
}
nrk_int_enable ();
_nrk_wait_for_scheduler ();
return NRK_OK;
}
inline void _nrk_wait_for_scheduler ()
{
//TIMSK = BM (OCIE1A);
do {
nrk_idle (); // wait for the interrupt to tick...
} while ((volatile uint8_t) nrk_cur_task_TCB->suspend_flag == 1);
//TIMSK = BM (OCIE1A) | BM(OCIE0);
}
int8_t nrk_wait_until (nrk_time_t t)
{
nrk_time_t ct;
uint8_t v;
nrk_time_get (&ct);
v = nrk_time_sub (&t, t, ct);
if (v == 0)
return NRK_ERROR;
//if(t.secstask_ID;
}