?? os.c
字號:
/*********************************************************************************************************
** Mini OS
** The Real-Time Kernel For Avr Atmega8/16 CPU
**
** (c) Copyright 2004-2004, wanghong
** All Rights Reserved
**
** V1.20
**
**
** Filename: os.c
** Created by: wanghong
** Date: 2004.09.05
** Description: Mini OS for Avr Atmega8/16 CPU
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Date:
** Description:
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#include "os_config.h"
#include "os.h"
#include <string.h>
OS_TASK_STATUS os_task_stat[OS_MAX_TASK_N]; // task's state
OS_MSG OS_MSG_MEM_TYP os_msg_q[OS_MAX_MSG_N]; // message pool
unsigned char os_msg_total; // total number of messages in message pool
unsigned char os_msg_cnt[OS_MAX_TASK_N]; // message counter of each task
SIGNAL_TYPE os_signal[OS_MAX_TASK_N]; // bit-mapped signal of each task
unsigned char os_task_rdy[(OS_MAX_TASK_N+7)/8]; // ready table of task list
unsigned char os_timer[OS_MAX_TASK_N]; // task's timer
unsigned int os_stkptr[OS_MAX_TASK_N+1]; // task's stack pointer(added 1 to fast the task switch process)
unsigned int os_stkptr_sw[OS_MAX_TASK_N]; // task's sw stack pointer
unsigned char os_task_curr; // id of the current task(0~MAX_TASK_N-1)
unsigned char os_task_next; // id of the next task to run
unsigned char os_isr_sig; // flag indicates there is(are) a task(s) has been set ready by an interrupt service routine.
unsigned char os_task_switching; // task switching is in process
unsigned long os_time; // os free run timer
#if OS_TASK_STAT_EN
unsigned long os_idle_ctr;
unsigned long os_idle_ctr_max;
signed char os_cpu_usage;
#endif
#if OS_STK_CHK_EN
signed char os_stk_usage;
signed char os_stk_usage_max;
#endif
static const unsigned char task_rdy_table[32]=
{
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
};
#define SET_TASK_READY(task_id) do{os_task_rdy[(task_id>>3)] |= task_rdy_table[task_id];}while(0)
#define CLR_TASK_READY(task_id) do{os_task_rdy[(task_id>>3)] &= ~task_rdy_table[task_id];}while(0)
/**********************************************************
* os_create_task: starts the defined task function using
* the task number specified by task_id. The task is
* marked as ready and is ready to execute
*
* @param task_id: task id
* @param ptask_entry: task's entry address
* @return 0: task create successfully,
* 0xff: task could not be started or if no task
* was defined using the specified task number
**********************************************************/
static unsigned char *p1;
static unsigned char *p2;
unsigned char os_create_task (unsigned char task_id, void (*task_entry)(void))
{
unsigned char i;
/* judge no err with the task to create */
if (task_id >= OS_MAX_TASK_N || // id err
task_entry == NULL || // task not defined
task_id == os_task_curr || // task already exist
os_task_stat[task_id].active
)
{
return (0xff);
}
/* move task entry address on the stack */
if (os_task_curr < task_id)
{
i = os_task_curr;
while (i < task_id)
{
i++;
p1 = (unsigned char *)os_stkptr[i]; // add stack base address
p2 = (unsigned char *)os_stkptr[i+1];
while (p1 != p2)
{
*(p1+2) = *p1;
p1--;
}
os_stkptr[i] += 2;
}
}
else if (os_task_curr > task_id)
{
/* adjust stack pointer, p1 = sp; sp -= 2; */
OS_ENTER_CRITICAL();
{
asm("push R0"); /* save r0/r1 */
asm("push R1");
asm("in r0, 0x3d"); /* stack pointer(N) */
asm("in r1, 0x3e");
asm("sts _p1,R0");
asm("sts _p1+1,R1");
asm("pop R1"); /* restore r0/r1 */
asm("pop R0");
asm("push R0"); /* sp -= 2(N-2) */
asm("push R0");
}
OS_EXIT_CRITICAL();
p1 += 2; /* p1 = sp(N) */
i = os_task_curr;
while (i > task_id)
{
p2 = (unsigned char *)os_stkptr[i] + 1; // task stack pointer 2
while (p1 < p2) // move 2 bytes data down on the stack
{
*(p1 - 2) = *(p1);
p1++;
}
p1 = (unsigned char *)os_stkptr[i] + 1; // task stack pointer 1
os_stkptr[i] -= 2; // the stack pointer of task -2 for moving down 2 bytes data
i--;
}
}
/*-- task timer init, copy the entry point address
of the task onto the stack, make task active/ready --*/
OS_ENTER_CRITICAL();
os_timer[task_id] = 0;
OS_EXIT_CRITICAL();
*((unsigned char *)((unsigned int)(os_stkptr[task_id] - 1))) = (unsigned char)((*(const unsigned int *)task_entry)>>8);
*((unsigned char *)((unsigned int)(os_stkptr[task_id]))) = (unsigned char)*(const unsigned int *)task_entry;
os_task_stat[task_id].active = 1;
os_task_stat[task_id].ready = 1;
SET_TASK_READY(task_id);
return (0);
}
/**********************************************************
* os_wait: halts the current task and waits for one or
* several events such as a time interval, a time-out, a message,
* or a bit-mapped signal from another task or interrupt.
*
* @param typ: event or events to wait for and can be any
* combination of the following manifest constants:
* (K_TMO, K_SIG, K_MSG).
* @param timeout: the number of timer ticks to wait for an
* interval event (K_IVL) or a time-out event (K_TMO).
* @param dummy: not used.
*
* @return EVENT_SIG: A signal was received.
* EVENT_MSG: A message was received.
* EVENT_TMO: A time-out has completed or an interval
* has expired.
* NOT_OK: The value of the typ argument is invalid.
**********************************************************/
#pragma ctask os_wait
unsigned char os_wait (unsigned char typ, unsigned char timeout, unsigned int dummy)
{
unsigned char event;
dummy = dummy; // prevent compiler warning.
if ((typ & (K_TMO|K_IVL|K_SIG|K_MSG)) == 0)
{
return NOT_OK;
}
event = 0;
OS_ENTER_CRITICAL();
/*-- 1. see if we wait for message --*/
if (typ & K_MSG)
{
os_task_stat[os_task_curr].waitmsg = 1;
}
else
{
os_task_stat[os_task_curr].waitmsg = 0;
}
/*-- 2. see if we wait for bit-mapped signal --*/
if (typ & K_SIG)
{
os_task_stat[os_task_curr].waitsig = 1;
}
else
{
os_task_stat[os_task_curr].waitsig = 0;
}
/*-- 3. see if we wait for a interval or time out --*/
if ((typ & K_IVL) || (typ & K_TMO))
{
os_task_stat[os_task_curr].waitto = 1;
}
else
{
os_task_stat[os_task_curr].waitto = 0;
}
/*-- 4.1 see if we wait for interval timer out --*/
if (typ & K_IVL)
{
unsigned char t_sum;
if (os_timer[os_task_curr] == 0)
{
goto normal_wait_a_timeout; // normal wait time out
}
/* if a time out happened, set a time-out event */
t_sum = os_timer[os_task_curr] + timeout;
if (t_sum == 0 || (t_sum >= os_timer[os_task_curr] && t_sum >= timeout))
{
os_timer[os_task_curr] = t_sum;
event = EVENT_TMO;
}
/* else wait for a time-out */
else
{
os_timer[os_task_curr] = t_sum;
}
}
/*-- 4.2 else see if we wait for time out --*/
else if (typ & K_TMO)
{
normal_wait_a_timeout:
/* see if we really want to wait for a time out */
os_timer[os_task_curr] = timeout;
if (timeout == 0)
{
event = EVENT_TMO; // no, set time-out event
}
}
/*-- 4.3 see if we get a time out event, return without task switch, user can reset
the task timer by "K_TMO" with timeout=0.
--*/
if (event == EVENT_TMO)
{
/* clear wait time-out, and time-out flag */
os_task_stat[os_task_curr].waitto = 0;
os_task_stat[os_task_curr].toflag = 0;
OS_EXIT_CRITICAL();
return EVENT_TMO;
}
/*-- 5. clear the ready bit if we have no message and no signal waitting --*/
if ((!os_task_stat[os_task_curr].waitmsg || os_msg_cnt[os_task_curr] == 0) &&
(!os_task_stat[os_task_curr].waitsig || os_signal[os_task_curr] == 0)
)
{
os_task_stat[os_task_curr].ready = 0;
CLR_TASK_READY(os_task_curr);
}
OS_EXIT_CRITICAL();
/*-- 6. perform a task switch --*/
asm("rjmp _os_switch_task");
}
/**********************************************************
* isr_send_signal: sends a bit-mapped signal to task task_id. If the
* specified task is already waiting for a signal, this
* function call readies the task for execution. Otherwise,
* the signal is stored in the signal flag of the task.
* The isr_send_signal function may be called only from interrupt service routine.
*
* @param task_id: task id
* @param signal: bit-mapped signal
* @return 0: if successful,
* 0xff: signal invalid or the specified task does not exist.
**********************************************************/
unsigned char isr_send_signal (unsigned char task_id, SIGNAL_TYPE signal)
{
if (OS_MAX_TASK_N <= task_id ||
0x0000 == signal
)
{
return 0xff;
}
os_signal[task_id] |= signal;
os_task_stat[task_id].sigflag = 1;
if (os_task_stat[task_id].waitsig)
{
os_task_stat[task_id].ready = 1;
SET_TASK_READY(task_id);
os_isr_sig = 1;
}
return 0;
}
/**********************************************************
* os_send_signal: sends a bit-mapped signal to task task_id. If the
* specified task is already waiting for a signal, this
* function call readies the task for execution. Otherwise,
* the signal is stored in the signal flag of the task.
* The os_send_signal function may be called only from task functions.
*
* @param task_id: task id
* @param signal: bit-mapped signal
* @return 0: if successful,
* 0xff: signal invalid or the specified task does not exist.
**********************************************************/
unsigned char os_send_signal (unsigned char task_id, SIGNAL_TYPE signal)
{
if (OS_MAX_TASK_N <= task_id ||
0x0000 == signal
)
{
return 0xff;
}
OS_ENTER_CRITICAL();
os_signal[task_id] |= signal;
os_task_stat[task_id].sigflag = 1;
if (os_task_stat[task_id].waitsig)
{
os_task_stat[task_id].ready = 1;
SET_TASK_READY(task_id);
}
OS_EXIT_CRITICAL();
return 0;
}
/**********************************************************
* os_get_signal: get a bit-mapped signal of the current task.
* This function may be called only from task functions.
*
* @param none
* @return: bit-mapped signal
* 0: no signal or the specified task does not exist.
**********************************************************/
SIGNAL_TYPE os_get_signal (void)
{
SIGNAL_TYPE signal;
OS_ENTER_CRITICAL();
signal = os_signal[os_task_curr]; // task get itself's signal
OS_EXIT_CRITICAL();
return signal;
}
/**********************************************************
* os_clear_signal: clear a bit-mapped signal of the current task.
* This function may be called only from task functions.
*
* @param signal: bit-mapped signal
* @return 0: if successful,
* 0xff: the specified task does not exist.
**********************************************************/
unsigned char os_clear_signal (SIGNAL_TYPE signal)
{
OS_ENTER_CRITICAL();
os_signal[os_task_curr] &= ~signal; // clear bit-mapped signal
if (os_signal[os_task_curr] == 0x0000)
{
os_task_stat[os_task_curr].sigflag = 0; // clear task signal flag
}
OS_EXIT_CRITICAL();
return 0;
}
/**********************************************************
* isr_send_message: send a message to a specific task.
* This function may be called only from interrupt service routine.
*
* @param task_id: the specified task to receive the message.
* @param msg_data: data to be sent. msg_data lenght must be 3 bytes.
* @return 0: if successful,
* !0: error code.
**********************************************************/
unsigned char isr_send_message (unsigned char task_id, unsigned char *msg_data)
{
if (OS_MAX_TASK_N <= task_id ||
os_task_stat[task_id].active == 0
)
{
return ERR_MSG_GENERAL;
}
if (OS_MAX_MSG_N <= os_msg_total)
{
return ERR_MSG_OVF;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -