OSAL系统框架专题2010-4-15 2:47:00

9. TI协议栈所用系统框架探讨。
51的系统往往不是太大,但是几十K的程序,也足以让一个初学者望而却步。我们首先忽略C语言本身的难度,光是系统框架也让生手读起来很吃力,再加上这种到处是API跟"define"的程序,还没有正式学习协议部分就已经让人在丛林中“迷路”了。

在接下来的一段时间内,我会以TI所用的系统框架为主线进行学习,希望大家共同探讨。。。

在层层迷雾中摸索了两天,终于拨云见日,那个心情啊,怎一个“爽”字了得~~~

可是怎么能把这么复杂的一个问题讲得清楚呢?嗯。。。还是先上图吧

注:为了便于直观,以下涉及到数据地址的地方都是由上而下,地址由高变低

第1节、各个任务是如何被调用到的?
我们还是先从main()函数开始,看看各个任务之间是如何协调工作的。
插播一句广告:在一切都看不清的时候,忽略次要,看主要因素 -- by outman from Zigbeetech

我们直接进入主循环的核心部分,看一下系统中的几个主要的任务是如何被调用,并开始自己的使命的?

看一段程序的时候,往往要从它的数据结构入手。我们先看一下,主循环中的两个关键数组,*tasksEvents与*tasksArr,从图一中我们可以看出来,tasksEvents这个数组存放的是从序号为0到tasksCnt,每个任务在本次循环中是否要被运行,需要运行的任务其值非0(用橙色表示),否则为0。而tasksArr数组则存放了对应每个任务的入口地址,只有在tasksEvents中记录的需要运行的任务,在本次循环中才会被调用到。--这节讲完了。。。

又有同学举手?什么?还没明白?恩。。。好像是不能讲这么短的。。。
那好吧,把main函数贴过来,我们一点一点看
初始化过程“先不管”,我们先看主循环(dead loop)

for(;;)  // Forever Loop
{
    uint8 idx = 0;
    Hal_ProcessPoll();  // 先不管1

do {
      if (tasksEvents[idx])  // 寻找最高优先级的任务来运行
      {
        break;
      }
    } while (++idx < tasksCnt);

if (idx < tasksCnt)
    {
      uint16 events;
      halIntState_t intState;

HAL_ENTER_CRITICAL_SECTION(intState);
      events = tasksEvents[idx];
      tasksEvents[idx] = 0;  // 本任务运行完了,要对其清空,为后面要运行的任务让路
      HAL_EXIT_CRITICAL_SECTION(intState);

events = (tasksArr[idx])( idx, events ); //最关键的一句话,如图一中,运行对应的任务

HAL_ENTER_CRITICAL_SECTION(intState);
      tasksEvents[idx] |= events;  // 本任务可能没完全完成,如果是这样,再次设置标志位,在下一次循环中继续执行
      HAL_EXIT_CRITICAL_SECTION(intState);
      }
    }

第2节、系统时间

我们知道,每个操作系统(虽然我不认为OSAL是一个标准的操作系统,但我们先这么叫着吧)都有一个“节拍”-tick,就像每一个“活人”都有心跳一样。那么OSAL的心跳有多快呢?--1ms。当然这个速度是可以设置的,在osal_timer_activate函数中开启了系统节拍,用TICK_TIME来定义其速度
#define TICK_TIME   1000   // Timer per tick - in micro-sec
注意:这个1000是micro-sec(微秒),而不是milli-sec(毫秒)!我刚开始的时候就是误以为是1000ms而耽误了不少时间。
那这个心脏是怎么跳动起来的呢?

这得从“定时器”说起,由于本文的重点不是讲单片机基础的,如果对这个名字还陌生的同学,那还是回去先看看基础再来看这个吧。2430有4个定时/计数器,其中timer4用来做系统计时。如果认为是timer2的同学请看一下halTimerRemap这个函数。在上述osal_timer_activate函数中,开启了系统计时,并将timer4的初始设为TICK_TIME(1000),这样timer4就开始了从1000开始的减计数,减到0以后呢?寄存器TIMIF会产生一个溢出标志,那么它会立即产生中断并进入中断服务程序吗?不会的。

我们看一下第1节主函数里的“Hal_ProcessPoll();  // 先不管1”(不管的东西早晚要管的,只是时间的问题而已)  这个函数里调用了HalTimerTick,这个函数就是专门来检查是否有硬件定时器溢出的,如果有的话会调用halTimerSendCallBack这个函数,对溢出事件做处理。

回过头来说系统节拍,那timer4在计数满1000(即1ms)后做了些什么事呢,那我们看一下halTimerSendCallBack 这个函数
void halTimerSendCallBack (uint8 timerId, uint8 channel, uint8 channelMode)
{
  uint8 hwtimerid;

hwtimerid = halTimerRemap (timerId);

if (halTimerRecord[hwtimerid].callBackFunc)
    (halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
}
这里面调用了“callBackFunc”函数,也就是说每个定时器溢出后都有一个callBackFunc函数,它在哪里呢,我们再看一下HalTimerConfig这个函数,它可以对每个定时器进行定义。那什么时候定义的呢?--InitBoard,即板子上电初始化的时候就做了这个定义的。我说什么来?“先不管”的东西,“后要管”的。。。

我们看到timer4的callBackFunc函数是Onboard_TimerCallBack,最终指向osalTimerUpdate,这个函数厉害了~
从上面的分析中我们知道它是每1ms被调用一次的,这样它就为应用程序提供了一个ms计时器,应用程序所用的定时往往以ms为单位足够了,这样的话就不用另外再占用硬件计时器了,毕竟只有4个嘛。。。同时这个函数还提供了一个系统时钟-osal_systemClock,看看它能计时多久吧,它是“uint32”型的,也就是2^32ms=49.7天,怎么样?你不会让这个系统时钟overflow吧:)

第3节、系统的消息处理机制

结合第1、2节中的内容,让我们一起进入到系统最核心的部分-消息处理中来吧(这个句型怎么这么耳熟~~~)

第1节中我们说了,tasksEvents数组存放了一个任务是否该被运行的序列,但是这个序列是如何产生的呢?如果了解了这个问题,那也就知道了OSAL系统的运作方式。
再插句广告:在浩如烟海的程序中搜索最重要的东西,就像大浪淘沙,其实也是蛮享受的一件事情--by outman from zigbeetech

source insight "ctr+/",整个项目搜索,我们发现了一个“osal_set_event”的函数是专门来设置tasksEvents的,但是似乎并不能帮到我们。继续搜!有两个很重要的地方引起了我们的注意:osalTimerUpdate和osal_msg_send这两个函数

osalTimerUpdate,这个称得上“厉害”的函数还记得吧?它会去设置tasksEvents?那不就是说,它可以让任务在主循环中被运行到?答对了,这就是它“厉害”的地方。。。那看看它运行任务的条件吧?
      // When timeout, execute the task
      if ( srchTimer->timeout == 0 )
      {
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );
... ...
也就是说,计时器溢出--恩。。。不多说了,我们埋个伏笔,先介绍另一个朋友-osal_start_timerEx,先看下它的自我介绍
/*********************************************************************
* @fn      osal_start_timerEx
*
* @brief
*
*   This is called to start a timer to expire in n mSecs.
*   When the timer expires, the calling task will get the specified event.
*
* @param   byte taskID - task id to set timer for
* @param   UINT16 event_id - event to be notified with
* @param   UNINT16 timeout_value - in milliseconds.
*
* @return  ZSUCCESS, or NO_TIMER_AVAIL.
*/
byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )

也就是说,它会开始一个timeout_value(ms)的计时器,当这个计时器溢出时,则会对taskID这个task,设置一个event_id,让这个任务在后面的主循环中运行到,但是是怎么实现的呢?还是要请osalTimerUpdate来帮忙。。。

那位同学说啥?复杂了,听不懂?
唉,还是上图吧


还是先从数据结构说起吧,不知道啥是“数据链表”的同学,把谭老师的书拿过来再读几遍。。。
这个表就是osalTimerUpdate函数的“任务表”,上面不是说过这个函数给应用程序提供了“软计时”了吗?就是体现在这里,osal_start_timerEx通过osalAddTimer向链表里添加了“定时任务”,由osalTimerUpdate来以ms为单位对这些“软定时器”减计数,溢出时,即调用osal_set_event,实现主循环里对任务的调用。

好了,到此讲了上面提到的"set event"函数中的一个osal_start_timerEx, 还有一个更厉害的还在外面呢,osal_msg_send,这就渐入佳境,进入最重要的消息处理机制了。。。

-- by outman 2010-4-14 18:00  下班啦,老婆在家等着回去一起做饭哪~~~晚上见~~~

为了更好地说明这个问题,还是拿一个具体的例子来讲比较直观。不过在这个笔记中,我尽量不涉及具体开发板,而讲一些通用的知识,因为这样会让更多的人受益。在TI官方zstack 2006中有4个例子,其中一个叫GenericApp最基本的通信的例程,如果没有安装zstack的同学可以到“本站专用下载贴”中下载。当然由于讲的是些比较通用的东西,所以手头有开发板的同学可以用自己的开发板来试验,效果更好。。。

在这样的通信例程中,一般会有一个按键触发,然后会和相邻的模块进行通信,当然由于这部分是讲OSAL的系统框架的,我们先不涉及通信的内容,只是看一下按键是如何产生的,及如何调用相应的接口程序。

按OSAL的模块定义,按键可能在哪层来?硬件服务相关的,恩。。。是不是在HAL层呢?到Hal_ProcessEvent看看?有个HalKeyPoll函数不是?恩,这就是检测按键的地方~~不过,我可不是像上面这样这么容易猜出来的,这几句话足足用了我大半个钟头呢。。。过程我不细说了,有兴趣的话我可以再补充一下。

在HalKeyPoll函数中,无论按键是ADC方式,或者是扫描IO口的方式,最后都会生成一个键值keys, 然后通过下面的语句来调用按键服务程序
  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcess))
  {
    (pHalKeyProcess) (keys, HAL_KEY_STATE_NORMAL);
  }
这里调用的服务程序,在InitBoard中被初始化为OnBoard_KeyCallback,这个函数又通过OnBoard_SendKeys运行下面语句
  {
    // Send the address to the task
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }
下面我们就看下osal_msg_send是如何向上级应用程序发送消息的。终于要讲消息量的数据结构了,好像绕得有点远。。。。还是先上图


在理解了消息量的数据链表后,再来理解osal_msg_send里的语句就不难了
  OSAL_MSG_ID( msg_ptr ) = destination_task;//设置消息数据对应是属于哪个任务的

// 将要发送的消息数据链接到以osal_qHead开头的数据链表中
  osal_msg_enqueue( &osal_qHead, msg_ptr );

// 通知主循环有任务等待处理
  osal_set_event( destination_task, SYS_EVENT_MSG );

这样用户任务GenericApp_ProcessEvent就收到一个按键的处理任务,并通过GenericApp_HandleKeys来执行相应的操作。

好了,现在应该对OSAL的消息处理机制有个了解了吧?我们再来复习一下这个按键的处理过程:任务驱动层Hal_ProcessEvent负责对按键进行持续扫描,发现有按键事件后OnBoard_KeyCallback函数向应用层GenericApp_ProcessEvent发送一个有按键需要处理的消息,最终由GenericApp_HandleKeys来负责执行具体的操作。

让我们再回到最初的问题,任务处理表tasksEvents是怎么被改动的呢?初始化程序、其他任务或者本任务主要通过下面几种方式对其操作:
1、设置计时器,当其溢出时,触发事件处理
2、直接通过任务间的消息传递机制触发
3

OSAL系统框架专题相关推荐

  1. Android Framework 窗口子系统 (08)窗口动画之动画系统框架

    该系列文章总纲链接:专题分纲目录 Android Framework 窗口子系统 本章关键点总结 & 说明: 导图是不断迭代的,这里主要关注➕ 左上角 Android 窗口动画系统部分(因为导 ...

  2. 跨链(8)跨链双雄Cosmos“系统框架”

    1. 系统框架 Cosmos是tendermint团队推出的一个支持跨链交互的异构网络, 一个分布式的独立并行区块链公链. 1.1 核心模块 tendermint core 简称tendermint, ...

  3. 跨链(6)波卡Polkadot “系统框架”

    1. 系统框架 Polkadot是一种集成平行链和中继链的多层多链架构. 多层中继链 多个平行链 1.1 三种链角色 中继链(Relay chain) 主要通信枢纽,提供统一的共识和安全保障 平行链( ...

  4. usb 系统消息_4. Autoware 系统框架概揽

    Autoware 系统架构如下图所示,非常的简洁和清晰.包括传感(sensing),计算(computering)和执行(aucuation)三个部分.在计算部分,包括感知(perception),决 ...

  5. rola物联网框架_如何搭建一个物联网系统框架?

    下面将谈到几个关键问题: 设备如何接入网络? 设备间如何通信? 物联网数据的用途? 如何搭建起一个物联网系统框架呢?它的技术架构又是怎么样呢? 物联网终端软件系统架构? 物联网云平台系统架构? 1.物 ...

  6. android系统框架()

    Android系统框架介绍:   1.大体框架: -src目录: 主要是完成java代码的编写 -assets目录: 资源目录 -res目录: 存储图片,布局文件和字符串,菜单等文件 -bin目录: ...

  7. 基于EasyDarwin流媒体云平台的智能视频监控系统框架

    基于EasyDarwin流媒体云平台的智能视频监控系统框架 EasyDarwin云平台作为国内较有影响力的开源流媒体平台,集流媒体分发,录像,信令交互为一体,目前已经被广泛应用到监控互联网各个领域:从 ...

  8. IOT(5)---物联网系统框架介绍

    转载: https://blog.csdn.net/robert_tin 物联网系统框架介绍 下面将谈到几个关键问题: 设备如何接入网络? 设备间如何通信? 物联网数据的用途? 如何搭建起一个物联网系 ...

  9. Java电商秒杀系统性能优化(一)——电商秒杀系统框架回顾

    电商秒杀系统框架回顾 项目简介 外部依赖 框架回顾 项目要点 项目中存在的问题 小结 课程是免费的,课程地址如下:SpringBoot搭建电商秒杀项目,课程真的很棒,作者的思路很清晰,建议各位读者可以 ...

最新文章

  1. 在vue中使用vuex,修改state的值示例
  2. card样式 layui_layui样式修改
  3. InnoDB引擎与MyIASM的一点总结
  4. 计算机视觉中的牛人贡献及其主页
  5. odoo10参考系列--网络控制器(Web Controllers)
  6. Informix 9.4和CSDK的安装
  7. Unix文件系统基本结构
  8. 静音抑制_正在研究利润以抑制创新
  9. MIT线性代数笔记十四讲 正交向量与正交子空间
  10. 物无定味适口者珍,Python3并发场景(CPU密集/IO密集)任务的并发方式的场景抉择(多线程threading/多进程multiprocessing/协程asyncio)
  11. 看什么书可以提高情商?提高情商的书籍排行榜
  12. UE5 GPU崩溃D3D丢失的终极解决办法
  13. win10安装linux虚拟机
  14. android+广播接收者category,广播接收者
  15. 关于使用媒体查询@meda失效原因的总结
  16. [转载] MATLAB快捷键
  17. 培训机构内幕--转载
  18. 关于ubuntu系统不显示wifi图标或WiFi无法连接问题解答
  19. 阿里云后台测试短信模板
  20. 二阶偏微分方程组 龙格库塔法_1、经典四阶龙格库塔法解一阶微分方程组

热门文章

  1. HDU 6608 FansBlog(粉丝博客)(MillerRabin算法+威尔逊算法)
  2. 2016 版 Laravel 系列入门教程(一)【最适合中国人的 Laravel 教程】
  3. Python--正则表达式在线验证的工具(regex)
  4. python pdf报告_利用python设计PDF报告,jinja2,whtmltopdf,matplotlib,pandas
  5. 怎么调出全局搜索_华为手机怎么设置全局搜索,怎么开启以及怎么关闭
  6. python股票查询系统_使用python获取股票的上市日期等基本信息
  7. 游戏资讯:预计在10月底至11月内, 版号审批将会恢复
  8. 报错:实体名称必须紧跟在 '' 后面
  9. 2021年 - 年终总结
  10. 【科软课程-信息安全】Lab12 SQL Injection Attack