一、raw_system.h相关代码
/*
****************************
*说明:中断信息类型
****************************
*/
enum {
RAW_TYPE_Q_FRONT, /*消息插入消息队列(不带消息大小,只唤醒一个任务)相应链表头部*/
RAW_TYPE_Q_END, /*消息插入消息队列(不带消息大小,只唤醒一个任务)相应链表尾部*/
RAW_TYPE_Q_ALL, /*消息插入消息队列(不带消息大小,唤醒全部任务)相应链表*/
RAW_TYPE_SEM, /*释放一个信号量(只唤醒一个任务)*/
RAW_TYPE_SEM_ALL, /*释放一个信号量(唤醒全部任务)*/
RAW_TYPE_SUSPEND, /*挂起任务*/
RAW_TYPE_RESUME, /*解除挂起任务*/
RAW_TYPE_Q_SIZE_FRONT, /*消息插入消息队列(带消息大小,只唤醒一个任务)相应链表头部*/
RAW_TYPE_Q_SIZE_END, /*消息插入消息队列(带消息大小,只唤醒一个任务)相应链表尾部*/
RAW_TYPE_Q_SIZE_ALL, /*消息插入消息队列(带消息大小,唤醒所有任务)相应链表*/
RAW_TYPE_EVENT /*设置事件标志*/
};
二、raw_task_0.h
#ifndef RAW_TASK_0_H
#define RAW_TASK_0_H
typedef struct EVENT_HANLDER {
void (*handle_event)(RAW_U8 ev, RAW_U8 *data);
} EVENT_HANLDER;/*任务0事件处理函数*/
typedef struct EVENT_STRUCT {
RAW_U8 ev; /*处理函数参数。在中断信息事件里,做任务0事件类型(详见raw_system.h的中断信息类型)*/
RAW_U8 *data; /*处理函数参数。在中断信息事件里,与该任务0事件绑定的中断信息结构指针*/
EVENT_HANLDER *p; /*该任务0事件的处理函数*/
} EVENT_STRUCT;/*任务0事件结构*/
typedef struct OBJECT_INT_MSG {
RAW_U8 type; /*中断信息的类型(详见raw_system.h)*/
void *object; /*指向中断信息的关联结构(任务控制块,信号量,消息队列等等)*/
struct OBJECT_INT_MSG *next; /*指向下一个中断信息结构体,用于链接链表*/
RAW_U8 opt; /*用于指定消息是插入到尾部还是头部,或者event里面用于设置RAW_OR或者 RAW_AND*/
void *msg; /*信息里附带的消息*/
RAW_U32 msg_size; /*消息大小*/
RAW_U32 event_flags; /*用在中断信息类型为RAW_TYPE_EVENT*/
} OBJECT_INT_MSG;/*中断里发送信息的结构体*/
void task_0_tick_post(void);
void raw_task_0_post(EVENT_HANLDER *p, RAW_U8 ev, RAW_U8 *data);
void raw_task_0_init(void);
RAW_U16 int_msg_post(RAW_U8 type, void *p_obj, void *p_void, RAW_U32 msg_size, RAW_U32 flags, RAW_U8 opt);
#endif
三、raw_task_0.c
#include <raw_api.h>
#if (CONFIG_RAW_TASK_0 > 0)
/*
*************************************************************
*名称:时钟节拍中断事件处理函数
*功能:更新节拍数,更新指定优先级ev第一个任务时钟片,一般是当前运行任务优先级
*通知定时器管理任务更新定时器(会执行到时的定时器处理函数),
*通过信号量来驱动定时器管理任务timer_task
*************************************************************
*/
void task_0_tick_handler(RAW_U8 ev, RAW_U8 *data)
{
data = data;
#if (CONFIG_RAW_USER_HOOK > 0)
raw_tick_hook();
#endif
/*主要处理超时了的任务*/
tick_list_update();
/*update task time slice if possible*/
#if (CONFIG_SCHED_FIFO_RR > 0)
caculate_time_slice(ev);
#endif
/*通知定时器管理任务更新定时器*/
#if (CONFIG_RAW_TIMER > 0)
call_timer_task();
#endif
}
/*
********************************************************
*功能:发送时钟节拍中断事件给任务0。
********************************************************
*/
void task_0_tick_post()
{
raw_task_0_post(&task_0_event_handler, raw_task_active->priority, 0);
}
/*
*********************************************************************************
*功能1(只针对传递中断信息):把处理函数,参数ev和data绑定在一起投递给
*任务0事件队列(task_0_events_queue)里的空闲任务0事件结构EVENT_STRUCT
*
*data:自定义(在传递中断信息时,该变量为中断信息块,在传递时钟节拍中断信号时,该值为0)
*ev:自定义(在传递中断信息时,该变量为中断信息类型,在传递时钟节拍中断信号时,该值应该为当前运行任务优先级值)
*p:对该任务0事件的执行函数(传递中断信息时,为msg_event_handler,传递时钟节拍中断信号时,为task_0_event_handler)
*
*********************************************************************************
*/
void raw_task_0_post(EVENT_HANLDER *p, RAW_U8 ev, RAW_U8 *data)
{
RAW_U32 snum;
RAW_SR_ALLOC();
/*任务0事件队列里的事件数已经达到队列的最大值*/
if(nevents_points == MAX_TASK_EVENT) {
RAW_ASSERT(0);
}
RAW_CPU_DISABLE();
/*取得队列事件尾部的第一个空闲块索引号*/
snum = (fevent_point + nevents_points) & (MAX_TASK_EVENT - 1);
/*更新任务0事件数*/
++nevents_points;
/*使任务0就绪*/
if (task_0_is_ready == 0) { //设置任务0就绪标志
task_0_is_ready = 1;
}
RAW_CPU_ENABLE();
/*填充索引尾snum的任务0事件块*/
task_0_events_queue[snum].ev = ev;
task_0_events_queue[snum].data = data;
task_0_events_queue[snum].p = p;
/*Update the debug information*/
if (nevents_points > peak_events) {
peak_events = nevents_points;
}
}
/*
********************************************************
*功能:任务0切换到其它普通任务
********************************************************
*/
static void task_0_switch()
{
RAW_SR_ALLOC();
RAW_CPU_DISABLE();
if (task_0_is_ready) {
RAW_CPU_ENABLE();
return;
}
get_ready_task(&raw_ready_queue);
CONTEXT_SWITCH();
RAW_CPU_ENABLE();
}
/*
************************************************************
*功能:任务0处理函数。任务0创建时被加入到就绪队列里。
*第一次执行任务0需要把该任务控制块取掉,该任务是个死循环,
*以后只在任务0就绪标志task_0_is_ready被置‘1’就会启动该任务。
*任务0就绪标志只在系统初始化时和接收到任务0事件时才被置‘1’。
************************************************************
*/
static void task_0_process(void *pa)
{
RAW_U8 ev;
RAW_U8 *data;
EVENT_HANLDER *receiver;
RAW_U8 done;
RAW_S32 i;
RAW_SR_ALLOC();
/*把任务0从就绪队列里摘除*/
list_delete(&raw_task_0_obj.task_list);
/*清除任务0对应task_bit_map里的就绪标志位*/
data = (RAW_U8 *)raw_ready_queue.task_bit_map;
*data &= ~1;
/*任务0的处理,死循环*/
while (1) {
done = 0;
/*在这个循环里面会把所有任务0事件都处理完成,最后切换到普通任务,当到任务0再次被激活了,又会回到该循环*/
while (done == 0) {
/*Get the message info and update it*/
RAW_CPU_DISABLE();
/*有任务0事件存在*/
if (nevents_points) {
/*对任务0事件队列的访问为FIFO*/
/*提取第一个任务0事件相应信息*/
ev = task_0_events_queue[fevent_point].ev;
data = task_0_events_queue[fevent_point].data;
receiver = task_0_events_queue[fevent_point].p; /*该事件处理函数*/
/*更新fevent_point和nevent_points*/
fevent_point = (fevent_point + 1) & (MAX_TASK_EVENT - 1);
--nevents_points;
RAW_CPU_ENABLE();
/*执行该事件处理函数*/
receiver->handle_event(ev, data); //执行事件处理函数
}
/*没有任务0事件出现*/
else {
/*清除任务0就绪标志*/
task_0_is_ready = 0;
RAW_CRITICAL_ENTER_CPU_ENABLE();
/*取出从task_bit_map的第一位到CONFIG_RAW_PRIO_MAX(不包括该位)的第一个‘1’与第一位的偏移量*/
i = bit_search_first_one(raw_ready_queue.task_bit_map, 1, CONFIG_RAW_PRIO_MAX - 1);
/*在0优先级之后有次高优先级*/
if (i >= 0) {
/*获取下个高优先级*/
raw_ready_queue.highest_priority = 1 + i;
}
/*0优先级之后没有就绪的任务*/
else {
#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif
}
/*退出临界区并且不执行调度(这个用使用RAW_CRITICAL_EXIT()也没事,因为task_0_is_ready已经被清零)*/
RAW_CRITICAL_EXIT_NO_SCHED();
/*从任务0切换到普通任务执行*/
task_0_switch();
done = 1;
}
}
}
}
#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
/*
*********************************************
*功能:这个函数用于处理中断里发出的信息,
*根据信息类型的不同调用不同的实现,详细见注释。
*
*data:要被处理的中断信息结构指针
*ev:指明data中断信息类型
*********************************************
*/
void int_msg_handler(RAW_U8 ev, RAW_U8 *data)
{
OBJECT_INT_MSG *int_msg;
RAW_SR_ALLOC();
/*取得中断信息结构指针*/
int_msg = (OBJECT_INT_MSG *)data;
switch (ev) { /*判断该data中断信息结构的类型,执行相应的处理*/
case RAW_TYPE_SUSPEND:/*如果中断信息类型为挂起任务类型*/
task_suspend((RAW_TASK_OBJ *)(int_msg->object));/*挂起中断信息结构里的object对应的任务*/
break;
case RAW_TYPE_RESUME:/*如果中断信息类型为解除挂起任务类型*/
task_resume((RAW_TASK_OBJ *)(int_msg->object));/*解除中断信息结构里的object对应的任务*/
break;
case RAW_TYPE_SEM:/*如果中断信息类型为信号量(唤醒一个任务)类型*/
semaphore_put((RAW_SEMAPHORE *)(int_msg->object), WAKE_ONE_SEM);/*释放一个object指定的信号量,唤醒一个阻塞任务*/
break;
case RAW_TYPE_SEM_ALL:/*如果中断类型是唤醒所有阻塞任务的信号量类型*/
semaphore_put((RAW_SEMAPHORE *)(int_msg->object), WAKE_ALL_SEM);/*释放一个object指定的信号量,唤醒所有阻塞与该信号量的任务*/
break;
case RAW_TYPE_Q_FRONT:/*如果是消息队列(LIFO)类型*/
msg_post((RAW_QUEUE *)(int_msg->object), int_msg->msg, SEND_TO_FRONT, WAKE_ONE_QUEUE);/*往object指定的消息队列传递消息,唤醒一个阻塞任务*/
break;
case RAW_TYPE_Q_END:/*如果是消息队列(FIFO)类型*/
msg_post((RAW_QUEUE *)(int_msg->object), int_msg->msg, SEND_TO_END, WAKE_ONE_QUEUE);
break;
case RAW_TYPE_Q_ALL:/*如果是消息队列(唤醒所有阻塞任务)类型*/
msg_post((RAW_QUEUE *)(int_msg->object), int_msg->msg, int_msg->opt, WAKE_ALL_QUEUE);
break;
case RAW_TYPE_Q_SIZE_FRONT:/*如果是带有消息大小的消息队列(LIFO)类型,唤醒一个阻塞任务*/
msg_size_post((RAW_QUEUE_SIZE *)(int_msg->object), int_msg->msg, int_msg->msg_size, SEND_TO_FRONT, WAKE_ONE_QUEUE);
break;
case RAW_TYPE_Q_SIZE_END:/*如果是带有消息大小的消息队列(FIFO)类型,唤醒一个阻塞任务*/
msg_size_post((RAW_QUEUE_SIZE *)(int_msg->object), int_msg->msg, int_msg->msg_size, SEND_TO_END, WAKE_ONE_QUEUE);
break;
case RAW_TYPE_Q_SIZE_ALL:/*如果是带有消息大小的消息队列(唤醒所有阻塞任务)类型*/
msg_size_post((RAW_QUEUE_SIZE *)(int_msg->object), int_msg->msg, int_msg->msg_size, int_msg->opt, WAKE_ALL_QUEUE);
break;
case RAW_TYPE_EVENT:/*如果是事件组类型*/
event_set((RAW_EVENT *)(int_msg->object), int_msg->event_flags, int_msg->opt);
break;
default:
RAW_ASSERT(0);
}
RAW_CPU_DISABLE();
/*处理完该中断信息后,要把该信息结构归还给空闲中断信息结构链表*/
int_msg->next = free_object_int_msg;
free_object_int_msg = int_msg;
RAW_CPU_ENABLE();
}
/*
***************************************
*功能:初始化中断信息处理。详细见注释
***************************************
*/
void int_msg_init()
{
OBJECT_INT_MSG *p_msg1;
OBJECT_INT_MSG *p_msg2;
RAW_U32 number;
/*初始化信息事件处理函数*/
msg_event_handler.handle_event = int_msg_handler;
/*取出中断空闲信息链表的最大信息数*/
number = OBJECT_INT_MSG_SIZE;
/*清空整个object_int_msg数组,这个空间用于下面链接成空闲信息链表*/
raw_memset(object_int_msg, 0, sizeof(object_int_msg));
/*是free_object_int_msg指向空闲信息链表的第一个中断信息结构*/
free_object_int_msg = object_int_msg;
/*下面是把该数组的元素链接成链表*/
p_msg1 = object_int_msg;
p_msg2 = object_int_msg;
p_msg2++;
while (--number) {
p_msg1->next = p_msg2;
p_msg1++;
p_msg2++;
}
/*最后一个节点没有后续节点*/
p_msg1->next = 0;
}
/*
*************************************************************************************
*功能:发出中断信息(中断信息需要传递给任务0进行处理,在此之前会把
*中断信息打包成EVENT_STRUCT传递给任务0事件队列task_0_events_queue)。
*
*type:指明中断信息类型(详见raw_system.h)
*p_obj:指向相应工程结构。(任务控制块,信号量结构体,消息队列结构体,事件结构体)
*p_void:附带消息指针。(如果是RAW_TYPE_Q或者RAW_TYPE_Q_SIZE类型)
*msg_size:附带消息大小。(如果是RAW_TYPE_Q_SIZE类型)
*flags: 用于RAW_TYPE_EVENT的信息类型,事件标志。
*opt:用于指定是置于尾部还是头部(SEND_TO_FRONT or SEND_TO_END),
*或者event里面用于设置RAW_OR或者RAW_AND。
*************************************************************************************
*/
RAW_U16 int_msg_post(RAW_U8 type, void *p_obj, void *p_void, RAW_U32 msg_size, RAW_U32 flags, RAW_U8 opt)
{
RAW_U8 *data;
RAW_SR_ALLOC();
RAW_CPU_DISABLE();
data = (RAW_U8 *)free_object_int_msg; /*取出第一个空闲中断信息块指针*/
if (free_object_int_msg == 0) {
RAW_ASSERT(0);
}
/*初始化该空闲中断信息块,各成员含义见rawtask_0.h的OBJECT_INT_MSG*/
free_object_int_msg->type = type;
free_object_int_msg->object = p_obj;
free_object_int_msg->msg = p_void;
free_object_int_msg->msg_size = msg_size;
free_object_int_msg->event_flags = flags;
free_object_int_msg->opt = opt;
/*更新free_object_int_msg(指向中断空闲信息链表的第一个空闲信息结构体)*/
free_object_int_msg = free_object_int_msg->next;
RAW_CPU_ENABLE();
/*把该中断信息块,类型,及对该中断信息块的处理函数绑定成任务0事件队列(task_0_events_queue)里的一个EVENT_STRUCT结构*/
raw_task_0_post(&msg_event_handler, type, data);
return RAW_SUCCESS;
}
#endif
/*
************************************************************
*功能:初始化任务0。创建0任务,设置任务0事件处理函数,
*在这里该函数用于处理时钟节拍事件(必须的),
*(在其它地方用户也可以自己定义个任务0事件使用自定义的处理函数)。
*使任务0就绪,初始化中断空闲信息块链表
************************************************************
*/
void raw_task_0_init()
{
/*创建任务0用于处理中断里发出的事件(时钟节拍事件或者中断信息事件)*/
raw_task_create(&raw_task_0_obj, (RAW_U8 *)"timer_object", 0,
0, 0, task_0_stack, TASK_0_STACK_SIZE, task_0_process, 1);
/*初始化时钟节拍事件处理函数*/
task_0_event_handler.handle_event = task_0_tick_handler;
task_0_is_ready = 1;
#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
int_msg_init();/*初始化中断空闲信息块链表*/
#endif
}
#endif