/************************************************************************* This file is part of aOS. aOS 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; either version 2 of the License, or (at your option) any later version. aOS 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 aOS; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Copyright 2001, 2002 Anssi Ylätalo ============ Jan 2005 Bruce Land Modified to include new functions --suspend --resume --sleep another task --check hw/data stack free bytes --unsleep another task --get/set task execution times --get/set dispatch counter --get task status --scheduler lock/unlock **************************************************************************/ aos_tcb *aos_task_create( void (*task)(void), UBYTE *hstack, UBYTE *dstack, UBYTE p ) { UBYTE *stk, *dstk, *hstk; UBYTE i; aos_tcb *tcb_new; AOS_ENTER_CRITICAL; tcb_new = (aos_tcb *)aos_ctbl.tcb_free_list; /* Get next free TCB */ if( tcb_new ) { /* TCBs left? */ /* Set up the hardware stack */ hstk = (UBYTE *)hstack + (AOS_TASK_HSTK_SIZE - 1); /* Stack begins in the end of array */ stk = hstk; *stk-- = (UBYTE)(task); /* Low part of task's address */ *stk-- = (UBYTE)(task >> 8); /* High part of task's address */ for(i=0;i<30;i++) /* Clear all other registers */ *stk-- = 0; *stk-- = 0x80; /* SREG with interrupts enabled */ /* Set up data stack */ dstk = (UBYTE *)dstack + (AOS_TASK_DSTK_SIZE - 1); /* Stack begins in the end of array */ aos_ctbl.tcb_free_list = (aos_tcb *)tcb_new->next_tcb; /* Release TCB from freelist */ tcb_new->next_tcb = (aos_tcb *)aos_ctbl.tcb_used_list; /* Link new TCB into TCB used list */ aos_ctbl.tcb_used_list = (aos_tcb *)tcb_new; tcb_new->datastk = (UBYTE *)dstk; /* Load data stack pointer to TCB */ tcb_new->hwstk = (UBYTE *)stk; /* Load hw stack pointer to TCB */ tcb_new->hstktop = (UBYTE *)hstk; //added by BRL to track stk tcb_new->dstktop = (UBYTE *)dstk; //added by BRL to track stk tcb_new->status = AOS_TASK_RUNNABLE; /* Make task runnable */ tcb_new->prio = (UBYTE)p; /* Set task's priority */ tcb_new->delay = (UWORD)0; /* No initial delay */ tcb_new->tcb_sem_q = (aos_tcb *)0; /* Initialize semaphore queue */ } AOS_EXIT_CRITICAL; return( tcb_new ); } //******************************************************** //utility which allows one task to sleep another //no call to the scheduler is needed here since the //task is not the current task. // USE aos_sleep if you are sleeping the current task!! void aos_sleep_task(aos_tcb *task, UWORD ticks) { AOS_ENTER_CRITICAL; task->delay = ticks; task->status = AOS_TASK_DELAYD; AOS_EXIT_CRITICAL; } //******************************************************* //utility which allows one task to UN-sleep another //if the task is dalayed. Task will restart on next tick. void aos_unsleep_task(aos_tcb *task) { AOS_ENTER_CRITICAL; if (task->status == AOS_TASK_DELAYD) task->delay = 0; AOS_EXIT_CRITICAL; } //******************************************************** //utility to allow tasks to suspend each other //need to schedule if the current task suspends itself void aos_suspend_task(aos_tcb *task) { AOS_ENTER_CRITICAL; if (task->status<2) //running or runnable task->status = AOS_TASK_SUSPENDED; else if (task->status==AOS_TASK_WAITING) task->status = AOS_TASK_SUSPENDED_WAIT; else if (task->status==AOS_TASK_DELAYD) task->status = AOS_TASK_SUSPENDED_DELA; if (aos_ctbl.tcb_current==task) _aos_schedule(); AOS_EXIT_CRITICAL; } //******************************************************** //utility to allow tasks to resume another task //need to reschedule IF the task has priority void aos_resume_task(aos_tcb *task) { char change ; AOS_ENTER_CRITICAL; change=0; if (task->status == AOS_TASK_SUSPENDED){ change=1; task->status = AOS_TASK_RUNNABLE; } else if (task->status == AOS_TASK_SUSPENDED_WAIT){ change=1; task->status = AOS_TASK_WAITING; } else if (task->status == AOS_TASK_SUSPENDED_DELA){ change=1; task->status = AOS_TASK_DELAYD; } //reschedule if reactivated task has priority if (change==1 && task->prio < aos_ctbl.tcb_current->prio) _aos_schedule(); AOS_EXIT_CRITICAL; } //******************************************************** //Find the high point of a task //hardware stack use int aos_task_hstk_chck(aos_tcb *task) { char *hbottom ; int free ; AOS_ENTER_CRITICAL; hbottom = (char *)task->hstktop - AOS_TASK_HSTK_SIZE + 1 ; while (*hbottom++ == 0) free++; return free; AOS_EXIT_CRITICAL; } //******************************************************** //Find the high point of a task //hardware stack use int aos_task_dstk_chck(aos_tcb *task) { char *dbottom ; int free ; AOS_ENTER_CRITICAL; dbottom = (char *)task->dstktop - AOS_TASK_DSTK_SIZE + 1 ; while (*dbottom++ == 0) free++; return free; AOS_EXIT_CRITICAL; } //******************************************************** //get the task time long aos_task_gettime(aos_tcb *task) { AOS_ENTER_CRITICAL; return task->ttime ; AOS_EXIT_CRITICAL; } //******************************************************** //set the task time void aos_task_settime(aos_tcb *task, ULONG time) { AOS_ENTER_CRITICAL; task->ttime = time ; AOS_EXIT_CRITICAL; } //******************************************************** //get the dispatch counter long aos_getdispatch() { AOS_ENTER_CRITICAL; return aos_ctbl.aos_dispcntr ; AOS_EXIT_CRITICAL; } //******************************************************** //set the dispatch counter void aos_setdispatch(ULONG count) { AOS_ENTER_CRITICAL; aos_ctbl.aos_dispcntr = count ; AOS_EXIT_CRITICAL; } //******************************************************** //get a task's status UBYTE aos_task_getstatus(aos_tcb *task) { AOS_ENTER_CRITICAL; return task->status ; AOS_EXIT_CRITICAL; } //******************************************************** //lock scheduler void aos_sched_lock(){ AOS_ENTER_CRITICAL; aos_ctbl.aos_schedrun = 0 ; AOS_EXIT_CRITICAL; } //******************************************************** //UNlock scheduler void aos_sched_unlock(){ AOS_ENTER_CRITICAL; aos_ctbl.aos_schedrun = 1 ; AOS_EXIT_CRITICAL; }