- 代碼: 選擇全部
/*-----------------------------------------------------------------
CopyRight (C) 1999, Dmitry Obukhov, dso@usa.net
--------------------------------------------------------------------
http://www.EmbeddedStuff.com
Compact Real-Time kernel (CRTK) for embedded applications
* It is really compact. It is not NT and even not CE. But...
* I wrote ISDN stack, running in this environment, this
* kernel can run on almost any 8-bit MCU. And it is compact.
* It means - no problem to add features, no problem to remove.
* No any line in assembler - you can transfer it in minutes to
* any new MCU.
*
* Of course, this is freeware version does not contains some nice
* features, such as software task slice control, automatic sleep
* mode, registers polling, embedded trace etc. If you want a
* commercial release - please contact me over e-mail.
* */
#include <stdlib.h>
#define MAXTASK 64
#define NORMAL_EXIT 1
typedef void (* FPTR )(void); // POINTER TO TIMER INTERRUPT HANDLER
typedef void (* VPTR )(void *); // POINTER TO TIMER FUNCTION
typedef void (* TPTR )(unsigned int * , void *); // Pointer to task
typedef struct
{
unsigned int * status; // Scheduler checks contents by this pointer
TPTR code; // Task code
void * data; // Task data for use same code for
// multiple logical streams
unsigned int priority; // Priority of this task
unsigned long id; // Task ID
unsigned int status_mode; // How to check status value (used as bit set)
unsigned int prev_status; // Prevoious value of status. Used in
// "polling-for-change"
unsigned int time_to_live;// Time (in tens of mS) to be in task
} SCELL;
//SCELL * task; // Array of task description cells
SCELL task[MAXTASK]; // Array of task description cells
int max_task; // Quantity of currently running tasks
FPTR wakeup_handler; // Pointer to wake up function
FPTR sleep_mode_handler; // pointer to deactivation procedure
unsigned long sleep_mode_count; // maximum of void loops till sleep
unsigned long void_loops; // void loops counter
unsigned char enable_sleep; // flag to enable/disable sleep mode
unsigned long last_id; // last ID issued
unsigned int time_to_be_in_task; // Value will be decremented in timer
// interrupt handler
void init_scheduler(void)
{
int i;
for (i=0;i<MAXTASK;i++)
{
task[i].status = NULL;
task[i].code = NULL;
task[i].data = NULL;
task[i].priority = ~0;//0xFFFF;
task[i].status_mode = 0; // Not used in this version
task[i].prev_status = 0;
task[i].id = 0; //0 is not valid ID
}
max_task = 0;
last_id = 0;
time_to_be_in_task = 0xFFFF;
}
void sort_tasks_according_to_priority(void)
{
int no_changes;
int i;
SCELL tmp;
if ( max_task<2 ) return; //No tasks or only one - nothing to sort :-)
no_changes = 0; // For loop entry
while ( !no_changes) // While all task list was not passed
{ // without any modifications
no_changes = 1;
for ( i=0; i<max_task-1; i++)
{
if ( task[i].priority > task[i+1].priority)
{// Task with higher priority located after low priority task
// Swap it and mark no_changes for next check
//Copy current task to tmp
memcpy(&tmp,&task[i],sizeof(SCELL));
//Move high priority task up
memcpy(&task[i],&task[i+1],sizeof(SCELL));
//Move low priority task down
memcpy(&task[i+1],&tmp,sizeof(SCELL));
no_changes = 0;
}
}
}
// Remove all empty tasks
while ( task[max_task - 1].status == NULL) max_task --;
}
unsigned long install_task(void * ttstatus,
TPTR tcode,
void * tdata,
unsigned int tpriority,
unsigned int task_mode,
unsigned int time_to_live)
{
unsigned int * tstatus = (unsigned int *) ttstatus;
if (max_task>=MAXTASK)
{
// OS_ERROR
// Oops! You have to compile your
// with larger task pool.
return 0;
}
task[max_task].status = tstatus;
task[max_task].code = tcode;
task[max_task].data = tdata;
task[max_task].priority = tpriority;
task[max_task].id = ++last_id;
task[max_task].status_mode = task_mode;
task[max_task].time_to_live = time_to_live;
max_task++;
/* More than 4,294,967,295 tasks was installed (and removed,
* probably). But something goes wrong. */
if (!last_id) /* os_error() */;
sort_tasks_according_to_priority();
return last_id;
}
unsigned int find_task(unsigned long id)
{
unsigned int i;
for ( i=0; i<max_task; i++)
{
if ( task[i].id == id) return i;
}
return 0xFFFF;
}
void remove_task(unsigned long id)
{
unsigned int tmp;
tmp = find_task(id);
if ( tmp != 0xFFFF) // Task is in the list. Remove it.
{
task[tmp].status = NULL; // Never will be called by scheduler
task[tmp].priority = 0xFFFF; // Move to the end of list
sort_tasks_according_to_priority();
//max_task--;
}
}
void uninstall_task(void * ttstatus,
TPTR tcode,
void * tdata)
{
unsigned int i;
for ( i=0; i<max_task; i++)
{
// This 3 parameters identifies the task
// Each one can be used with different data but together we never kill
// wrong task
if ( task[i].status == ttstatus &&
task[i].code == tcode &&
task[i].data == tdata)
{
task[i].status = NULL; // Never will be called by scheduler
task[i].priority = 0xFFFF; // Move to the end of list
sort_tasks_according_to_priority();
//max_task--;
return;
}
}
}
void change_task_priority(unsigned long id, unsigned int p)
{
unsigned int tmp;
tmp = find_task(id);
if ( tmp != 0xFFFF) // Task is in the list.
{
task[tmp].priority = p; // Change priority
sort_tasks_according_to_priority(); // Arrange list
}
}
int stop_scheduler;
void scheduler(void)
{
int current_task;
stop_scheduler = 0;
current_task = 0;
while (!stop_scheduler)
{
if ( *task[current_task].status )
{
/////////////////////////////////////////////////////////////////
// ----------------------------------------------TASK ENTRY POINT
/////////////////////////////////////////////////////////////////
(task[current_task].code)(task[current_task].status, ////////////
task[current_task].data); ////////////
/////////////////////////////////////////////////////////////////
current_task = 0; // Restart from task with lowest priority
}
else if (++current_task >= max_task)
{
current_task = 0;
}
}
}
void os_shutdown(int code)
{
stop_scheduler = code;
}
#define CRTK_TASK(x) void x(unsigned int * task_status, void * task_data)
/*---------------------------------------------------------------
* --------------------------------------------------------------
* --------------------------------------------------------------
* --------------------------------------------------------------
* ------------------------------------------------------------*/
void hardware_init(void)
{
// turn on your whistles here
}
void os_init(void)
{
// A lot of stuff and
init_scheduler();
}
void os_finish(void)
{
// empty in free version
}
void application_finish(void)
{
// empty in free version
}
// Actually this 3 functions are in different module
unsigned int task_flag; // increment it in interrupt
unsigned long task_counter;
unsigned int run_always;
CRTK_TASK(just_dummy_task)
{
unsigned int * flag = (unsigned int *) task_status;
unsigned long * count = (unsigned long *) task_data;
*flag = 0;
(*count) ++;
// Blink a lamp, write "Hello, world"
}
CRTK_TASK(read_keyboard)
{
unsigned int * flag = (unsigned int *) task_status;
if (kbhit()) *flag = getch();
if (*flag == 0x1B) os_shutdown(NORMAL_EXIT);
}
void application_init(void)
{
install_task(&task_flag, // if this integer not zero
just_dummy_task, // Call this function
&task_counter, // With pointer to this structure
0x1000, // Task priority
0,0); // Not used in public version
run_always = 0xFFFF;
install_task(&run_always, // if this integer not zero
read_keyboard, // Call this function
NULL, // With pointer to this structure
0xFFFF, // Task priority
0,0); // Not used in public version
}
void main(void) // Here is a C program start point
{
void far * memory;
hardware_init(); // User must write this function.
// It is specific to user's hardware
os_init(); // Init all kernel's stuff
application_init(); // User must write this function.
// It is specific to user's
// application
scheduler(); // Let it go!!!!
application_finish(); // Finish all application activity
// and clear all allocated buffers
os_finish(); // Now this code has meaning for
// PC_EMULATION only. If program
// runs on the board, this code is
// unreachable
}