作为分析的内核版本2014-04-15,基于1.05正式版,blogs我们会跟上的内核开发进度的最新版本,如果出现源代码的目光”???”的话。没有深究的部分是理解。

Raw-OS官方站点:http://www.raw-os.org/

Raw-OS托管地址:https://github.com/jorya/raw-os/

在真正介绍状态机编程之前。还是先介绍一下一些Raw-OS关于状态机编程的主要的东西。做做前戏是非常有必要的。让后来来得更有感觉~嗯嗯~就是这种~

那这篇就先介绍一下Raw-OS的空暇事件的内核运行过程,据Raw-OS作者txj大大的介绍,状态机编程结合事件触发机制,双剑合璧才干发挥很很好的功效。可是小弟我到如今还不能很好的领悟Raw-OS中状态机编程的精髓啊~精啊~啊~

所谓的事件触发机制,在Raw-OS内核表现出来的就是一套用户APIs。事实上这里就解说一下API的运行原理而已,为下一节開始的状态机编程(fsm、hsm)打打预防针。嗯嗯~就是这种

一、事件触发原理

首先,先来看看一张图

这张图就是事件触发的在Raw-OS运行的流程图,这里就先了解一下概念,是了解哈~亲~

首先就是图上的OBJ、OBJ是什么呢?记住一个名词,活动对象。仅仅是先记住“活动对象”这个名词,所谓的状态机编程。就是对活动对象定义和编写状态函数,那什么又是状态函数呢,就是事件的处理过程函数,处理的过程函数好理解,就是详细的运行操作嘛,那尼玛什么又是事件?事件嘛,事实上就是一个信号,尼玛什么信号啊,给老子详细点。

好好,举个样例,

本屌是一个程序猿。程序猿就是本屌,那么本屌就能够抽象成一个活动对象

那么状态机编程呢?就是定义和编写状态过程,比如本屌比較正常的一天的工作就是,写代码,然后累的时候去抽烟,领导不在的时候就偷懒。刷糗百的时候选择拉翔。最后空暇的时候就去文员办公室调剂一下。调戏为数不多的小妹妹们

相应于事件触发的机制来讲一讲~

有时候本屌的责任心就是比較强。爱岗敬业,常常督促自己完毕当日的代码编写工作,那么本屌就会给自己发送一个:尼玛。赶紧干活的事件消息。再比方说项目组的文员常常有事没事就会要你跟一下项目进度。或者一些琐碎的事情,那么文员就会给你发送一个:妈蛋。给老娘滚过来报告进度的事件消息。再比方说,老大有时候无聊会找你组队抽个烟,吐槽一下公司的垃圾方面,那就就会给你发送一个:来来来,走一个的事件信号......

然后,本屌会接收到非常多的事件信号,这些事件都是要处理的。都是有优先级的,比方我先会去文员那里报告进度,得罪女人非常麻烦的,你懂的,然后才会去跟老大“走一个”,最后才会去完毕本屌的本质工作:写代码。所以。在接收信号的时候。我自己会对事件信号排序,然后存在我的脑子里。在抽象框图就是活动对象的buffer中,到这里能够略微理解一点没有。

事件调度就是在我脑子里接收并排序好的事件信号,一个个去完毕它,拿到一个事件信号。就去运行相应的工作,也就是运行活动对象的状态函数,状态机编程详细就是干这个东西,怎么去定义状态,怎么样去编写状态运行函数的方法论,完事。

二、Raw-OS事件触发相关概念

然后如今详细到Raw-OS的事件触发的详细代码里面。

在Raw-OS中。能够定义最多64个活动对象,就好比一个公司有众多屌丝程序猿一样,然后每一个活动对象都有自己的优先级。就好比屌丝中也有累不死然后喜欢天天加班的屌。他们优先级是非常高的,通常分配到他们的资源是非常的多的,好比我所在的公司,组长尼玛都是天天加班在办公室里面做码神,可是好比我这种可有可无的屌丝就不会干这事,常常一下班就开溜。项目也不多。钱也拿得少,所以优先级非常低。

那么在Raw-OS中的。活动对象的优先级大小是依照定义时的顺序先后排列的。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG9ydG9pc2VjaGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

也就是说。先定义OBJ0,那么OBJ0就是优先级最高,为0。比方我先定义OBJ63,那么OBJ63就是最高优先级的活动对象。总之,先定义的活动对象比后定义的活动对象的优先级高。全部定义的活动对象都放在active_idle_task[]全局数组里面,Raw-OS在事件触发系统初始化时,就会初始化这些定义的活动对象。

每一个活动对象,在内核中由两部分组成

活动对象包括:

1.关于其自身的状态机。也就是说。包括属于这个活动对象的可能的全部状态和状态函数的定义

2.一个用于接收事件信号的消息队列(Queue)

至于内核代码,就是抽象成几个变量

如今再利用上面的样例拓展一下,对于项目组的文员,也能够抽象成活动对象,然后老大也能够抽象成活动对象。领导也是一个鸟样,相同是活动对象

那么对于事件消息。活动对象能够给活动对象发送事件消息,另外硬件中断也能够给活动对象发送事件消息~硬件中断怎么理解。妈蛋如今写单片机程序你说你理解不了中断,卧槽,你TM是在逗我吗?

好好。接下来再说说。有几个Raw-OS系统默认能够发送的事件信息,一个是入口事件ENTRY,一个是初始化事件INIT。一个是出口事件EXIT,最后一个是超时事件TIMEOUT。

这几个信号在下节进入状态机详细编程的时候再讲。这里先记住就能够了~

举个超时事件TIMEOUT的样例

比方刚才项目管理组的文员叫本屌去汇报进度,可是本屌在忙其它的事情,距离叫本屌去汇报进度已经过去了一两个小时。文员拍案而起,给本屌发了条消息:“狗日的,老娘日理万机,还不给老娘滚过来汇报一下”,得罪女人非常麻烦的~你懂的。于是我给自己发送一个超时信号。是时候要去安抚一下那帮面目狰狞的女汉子暴躁的情绪了,超时信号就是这样,活动对象等待一个特定的事件发生。然后我们给他定义了一段等待事件,假设在等待事件里面特性的时间还没发生。就给自己发送一个timeout的事件,运行timeout的状态函数。

而等待超时的活动对象,都会放到idle的tick list中,这个和之前讲过Raw-OS内核的软件定时器tick list是一样的原理

最后讲讲queue这个东东。之前讲过的全部关于queue的原理在这里相同适用,这里只介绍发送事件消息时,能够发往消息queue的前端和后端。发送到queue前端的消息,在活动对象激活时会首先被处理,所以。消息按优先级大小排列就是依据发送给queue的事件消息的顺序

三、事件触发系统API代码具体解释

接下来就直接看凝视过的代码了~依照上面的概念去分析代码,结合凝视,非常easy看懂

活动对象初始化

void idle_event_init(void)
{
ACTIVE_EVENT_STRUCT *temp;
RAW_U8 i; /* 初始化idle任务队列中的全部活动对象。依据Raw-OS内核规定。活动对象的最大数为64 */
for (i = 0; i <= MAX_IDLE_EVENT_TASK - 1; i++) {
temp = active_idle_task[i].act; RAW_ASSERT(temp != 0); temp->prio = i;
temp->head = 0;
temp->tail = 0;
temp->nUsed = 0; /*
* priority_bit_y定义为组别优先级
* priority_bit_x定义为每一个组别活动对象优先级
* 分8个组别,每一个组别含8个活动对象
*/
temp->priority_x = i & 0x7;
temp->priority_y = i >> 3; temp->priority_bit_y = (RAW_U8 )(1 << temp->priority_y);
temp->priority_bit_x = (RAW_U8 )(1 << temp->priority_x); } /* 初始化idle的tick链表 */
list_init(&raw_idle_tick_head); }

发送事件消息到queue前端

RAW_U16 idle_event_front_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para)
{ #if (CONFIG_RAW_ZERO_INTERRUPT > 0)
/* 开启task 0后,消息由task 0转发??? */
if (raw_int_nesting && raw_sched_lock) {
return int_msg_post(RAW_TYPE_IDLE_FRONT_EVENT_POST, me, para, sig, 0, 0);
}
#endif /* 向活动对象的queue发送消息,这里选择发送到queue的前端,紧急消息 */
return event_post(me, sig, para, SEND_TO_FRONT);
}

发送事件到queue后端

RAW_U16 idle_event_end_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para)
{ #if (CONFIG_RAW_ZERO_INTERRUPT > 0)
/* 开启task 0后,消息由task 0转发??? */
if (raw_int_nesting && raw_sched_lock) {
return int_msg_post(RAW_TYPE_IDLE_END_EVENT_POST, me, para, sig, 0, 0);
}
#endif /* 向活动对象的queue发送消息,这里选择发送到queue的末端。一般消息 */
return event_post(me, sig, para, SEND_TO_END);
}

事件发送核心代码

RAW_U16 event_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para, RAW_U8 opt_send_method)
{ ACTIVE_EVENT_STRUCT_CB *acb; RAW_SR_ALLOC();
/* 依据活动对象的优先级,获取其在idle队列中的活动对象控制块 */
acb = &active_idle_task[me->prio]; RAW_CRITICAL_ENTER(); /*
* nUsed变量用来存放活动对象中queue中存在的消息数量
* and变量表示的是活动对象中queue的大小
*
* 这里推断当活动对象的存在消息数量超过活动对象queue存放消息数量的大小关系,溢出返回
*/
if (me->nUsed == acb->end) { RAW_CRITICAL_EXIT();
return RAW_IDLE_EVENT_EXHAUSTED;
} /*
* 在这里,回想raw_queue_buffer这个模块,活动对象存放消息的queue也是一个环形buffer
*
* 发送消息到活动对象queue的末端
*/
if (opt_send_method == SEND_TO_END) {
/* 向buffer头指针位置写入活动对象信号 */
acb->queue[me->head].sig = sig;
/* 向buffer头指针位置写入活动对象信号參数 */
acb->queue[me->head].para = para;
/* 当head指针到达buffer的末端时,重置回到buffer起始位置 */
me->head++;
if (me->head == acb->end) {
me->head = 0;
}
} else {
/* 当tail指针到达buffer的起始位置时,重置回到buffer末端 */
if (me->tail == 0) {
me->tail = acb->end;
}
me->tail--;
/* 向buffer尾指针位置写入活动对象信号 */
acb->queue[me->tail].sig = sig;
/* 向buffer尾指针位置写入活动对象信号參数 */
acb->queue[me->tail].para = para;
}
/* 消息数量+1 */
++me->nUsed; /*
* 当活动对象存在消息时,活动对象就会得到活动对象优先级大小raw_rdy_tbl[]和组别优先级大小raw_idle_rdy_grp信息
*
* 存在消息的活动对象就能够依据raw_rdy_tbl[]和raw_idle_rdy_grp查表得到存在消息的最高优先级活动对象
*/
if (me->nUsed == 1) {
raw_idle_rdy_grp |= acb->act->priority_bit_y;
raw_rdy_tbl[acb->act->priority_y] |= acb->act->priority_bit_x;
} RAW_CRITICAL_EXIT(); return RAW_SUCCESS;
}

给活动对象指定超时时间

/*
* 这个函数相当于给活动对象创建一个软件定时器。可是简化非常多raw_timer的工作
* 可是这个活动对象的定时器仅仅有一次超时的功能,超时会向创建活动对象软件定时器定义的活动对象发送超时信号
*/
RAW_U16 idle_tick_arm(ACTIVE_EVENT_STRUCT *me, RAW_TICK_TYPE ticks)
{
RAW_U16 tick_ret; RAW_SR_ALLOC();
/* 中断中不能创建活动对象的定时器 */
if (raw_int_nesting) {
return RAW_NOT_CALLED_BY_ISR;
}
/* 创建活动对象定时器时,超时时间大小不能为0 */
if (ticks == 0) {
return RAW_IDLE_TICK_ADD_FAILED;
} RAW_CPU_DISABLE();
/* 将定时器信息写入到活动对象中。并增加到idle_tick_list链表,在系统tick中断中调用idle_tick_isr()等待超时 */
if (me->tick_ctr == 0) {
me->tick_ctr = ticks;
list_insert(&raw_idle_tick_head, &me->idle_tick_list);
tick_ret = RAW_SUCCESS;
} else {
tick_ret = RAW_IDLE_TICK_ADD_FAILED;
} RAW_CPU_ENABLE(); return tick_ret;
}

在系统时间中计算超时时间

/*
* 假设raw_time_tick()函数一样,在系统tick isr中调用。更新idle_tick_list链表,用来计算活动对象超时时间
*/
void idle_tick_isr(void)
{
ACTIVE_EVENT_STRUCT *a; LIST *head;
LIST *iter;
LIST *iter_temp; head = &raw_idle_tick_head;
iter = head->next; /* 历遍idle_tick_list,推断idle_tick_list中有没有等待超时的活动对象 */
while (iter != head) { a = list_entry(iter, ACTIVE_EVENT_STRUCT, idle_tick_list);
iter_temp = iter->next;
/* 更新活动对象超时时间 */
if (a->tick_ctr) {
--a->tick_ctr;
/* 活动对象超时时,向活动对象发送timeout信号,并以0參数传入活动对象 */
if (a->tick_ctr == 0) {
/* 这里说明活动对象的超时是一次超时,超时后删除活动对象的软件定时器 */
list_delete(iter);
idle_event_end_post(a, STM_TIMEOUT_SIG, 0);
}
} iter = iter_temp;
}
}

终止活动对象等待指定信号

/*
* 取消活动对象的软件定时器
* 某些时候某些情况发生,我们不须要激活活动对象。所以取消还在等到超时的活动对象的软件定时器
*/
RAW_U16 idle_tick_disarm(ACTIVE_EVENT_STRUCT *me)
{
RAW_U16 tick_ret; RAW_SR_ALLOC();
/* 中断中不能取消 */
if (raw_int_nesting) {
return RAW_NOT_CALLED_BY_ISR;
} RAW_CPU_DISABLE(); /* 等待超时的活动对象中删除软件定时器信息。并从idle_tick_list链表移除超时信息 */
if (me->tick_ctr) {
list_delete(&me->idle_tick_list);
me->tick_ctr = 0;
tick_ret = RAW_SUCCESS;
} else {
tick_ret = RAW_IDLE_TICK_DELETE_FAILED;
} RAW_CPU_ENABLE(); return tick_ret;
}

事件触发系统调度

void idle_run(void)
{
ACTIVE_EVENT_STRUCT *a;
STATE_EVENT temp; ACTIVE_EVENT_STRUCT_CB *acb;
RAW_U8 x;
RAW_U8 y;
RAW_U8 idle_high_priority; RAW_SR_ALLOC(); while (1) { RAW_CRITICAL_ENTER(); /* 当任一个活动对象存在消息时。即有idle任务有事件发生时 */
if (raw_idle_rdy_grp) { /* 查找位图表,通过64个优先级的活动对象的分组情况(raw_idle_rdy_grp、raw_rdy_tbl[])逆运算得到活动对象优先级 */
y = raw_idle_map_table[raw_idle_rdy_grp];
x = y >> 3;
idle_high_priority = (y + raw_idle_map_table[raw_rdy_tbl[x]]); /* 依据优先级从idle任务自己定义的活动对象tcb的结构体数组中取出活动对象tcb */
acb = &active_idle_task[idle_high_priority];
/* 从活动对象tcb中取出活动对象结构体 */
a = active_idle_task[idle_high_priority].act; /* 活动对象消息数量-1 */
--a->nUsed;
/* 当活动对象全部消息处理完成时 */
if (a->nUsed == 0) {
/* 活动对象没有消息时,清除其raw_rdy_tbl[]中raw_idle_rdy_grp的相应位 */
raw_rdy_tbl[a->priority_y] &= (RAW_U8)~a->priority_bit_x;
/* 假设清除活动对象后,所在组别中也无其余活动对象,清楚组别标志位 */
if (raw_rdy_tbl[a->priority_y] == 0) { /* Clear event grp bit if this was only task pending */
raw_idle_rdy_grp &= (RAW_U8)~a->priority_bit_y;
}
}
/* 在活动对象控制块的queue中的tail位置取出信号和信号參数 */
temp.sig = acb->queue[a->tail].sig;
temp.which_pool = acb->queue[a->tail].para; /* queue中的tail指针后移。丢弃取出使用后的消息,而且当移动到queue末端时,重置到queue头部 */
a->tail++;
if (a->tail == acb->end) {
a->tail = 0;
} RAW_CRITICAL_EXIT(); /*
* 取出消息后,依据系统宏选项运行有限状态机或者层级状态机
* 在运行状态机的过程。是依据temp消息运行相应的运行选项
*/
#if (RAW_FSM_ACTIVE > 0)
fsm_exceute(&a->super, &temp);
#else
hsm_exceute(&a->super, &temp);
#endif } /* 假设全部活动对象都不存在消息时,运行用户自己定义的idle事件钩子函数,通常在没有消息处理时进入硬件低功耗休眠 */
else {
RAW_CRITICAL_EXIT();
RAW_CPU_DISABLE();
if (raw_idle_rdy_grp == 0) {
/* 用户idle事件钩子函数 */
idle_event_user();
}
RAW_CPU_ENABLE();
}
}
}

在这里为止,事件触发系统,也就是事件触发API介绍完成,也介绍了一般性的概念,比如活动对象。事件信号。状态运行函数,这一节着重理解决方案就可以了概念,以下部分详细描述了开始fsm状态机编程。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Raw-OS备用事件源代码分析的更多相关文章

  1. 基于raw os 的事件触发系统

    Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...

  2. UiAutomator喷射事件的源代码分析

    上一篇文章<UiAutomator源代码分析之UiAutomatorBridge框架>中我们把UiAutomatorBridge以及它相关的类进行的描写叙述,往下我们会尝试依据两个实例将这 ...

  3. Android事件分发机制源代码分析

    小小感慨一下,做android有一段时间了,一直以来都是习惯整理笔记存到有道笔记上,没有写博客的习惯. 以后逐步分类整理出来,也算"复习"一遍了 - _ - . android的事 ...

  4. Monkey源代码分析番外篇之Android注入事件的三种方法比較

    原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV 往下分析 ...

  5. monkey源代码分析之事件注入方法变化

    在上一篇文章<Monkey源代码分析之事件注入>中.我们看到了monkey在注入事件的时候用到了<Monkey源代码分析番外篇之Android注入事件的三种方法比較>中的第一种 ...

  6. Monkey源代码分析之事件注入

    本系列的上一篇文章<Monkey源代码分析之事件源>中我们描写叙述了monkey是怎么从事件源取得命令.然后将命令转换成事件放到事件队列里面的.可是到如今位置我们还没有了解monkey里面 ...

  7. 转:SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

  8. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

  9. 【Android开源项目分析】android轻量级开源缓存框架——ASimpleCache(ACache)源代码分析

    转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46379055 ASimpleCache框架源代码链接 https://github ...

随机推荐

  1. 【30.36%】【codeforces 740D】Alyona and a tree

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  2. 使用Perl处理Excel之DMA映射

    使用Perl处理Excel之DMA映射 功能 通道处理,将各个通道的外设映射到通道上 外设ack信号处理 脚本执行情况 顶层Perl脚本(dma_parse.pl) 将上述两个功能脚本整合,便于调用 ...

  3. C语言实现字符串截取函数left、mid和right

    作者:iamlaosong C语言字符串截取须要自己编程实现,只是.网络时代,自然不用自己从头写了.网上各种方法的实现代码已经多如牛毛了,这儿抄录一个感觉不错的备案. #include <std ...

  4. mycat 离散分片 -&gt; 程序指定分区的分片

    1.程序指定分区的分片 此规则是在运行阶段有应用自主决定路由到那个分片. 此方法为直接依据字符子串(必须是数字)计算分区号(由应用传递參数.显式指定分区号). 2,加入配置文件 在function.x ...

  5. NYOJ 364 田忌赛马

    田忌赛马 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描写叙述 Here is a famous story in Chinese history. "That ...

  6. 微信测试号开发之四 获取access_token和jsapi_ticket

    原文:https://blog.csdn.net/qq_37936542/article/details/78549233 access_token:公众号的全局唯一接口调用凭据,公众号调用各接口时都 ...

  7. 【24.91】【Tsinsen 1302】&【BZOJ 2626】JZPFAR

    时间限制:5.0s   内存限制:256.0MB   总提交次数:547   AC次数:137   平均分:40.31 将本题分享到:        查看未格式化的试题   提交   试题讨论 试题来 ...

  8. 前端工具WebStorm好在哪里?(带详细破解教程)

    前端工具WebStorm好在哪里?(带详细破解教程) 一.总结 1.WebStorm对html特别是HTML5和JS的智能提示简直堪称大神. 2.WebStorm足够的轻量级. 3.WebStorm对 ...

  9. 细说Oracle中NULL值

    1.NULL是什么? NULL表示UNKNOW(未知),其不代表不论什么值. 比如一行中某列没有不论什么值即为NULL. ORACLE同意不论什么一种数据类型的字段为空,除了下面两种情况: 1)主键字 ...

  10. Angular.js回想+学习笔记(1)【ng-app和ng-model】

    Angular.js中index.html简单结构: <!doctype html> <html ng-app> <head> <script src=&qu ...