OSAL解读笔记.docx

上传人:b****7 文档编号:16389963 上传时间:2023-07-13 格式:DOCX 页数:56 大小:48.02KB
下载 相关 举报
OSAL解读笔记.docx_第1页
第1页 / 共56页
OSAL解读笔记.docx_第2页
第2页 / 共56页
OSAL解读笔记.docx_第3页
第3页 / 共56页
OSAL解读笔记.docx_第4页
第4页 / 共56页
OSAL解读笔记.docx_第5页
第5页 / 共56页
OSAL解读笔记.docx_第6页
第6页 / 共56页
OSAL解读笔记.docx_第7页
第7页 / 共56页
OSAL解读笔记.docx_第8页
第8页 / 共56页
OSAL解读笔记.docx_第9页
第9页 / 共56页
OSAL解读笔记.docx_第10页
第10页 / 共56页
OSAL解读笔记.docx_第11页
第11页 / 共56页
OSAL解读笔记.docx_第12页
第12页 / 共56页
OSAL解读笔记.docx_第13页
第13页 / 共56页
OSAL解读笔记.docx_第14页
第14页 / 共56页
OSAL解读笔记.docx_第15页
第15页 / 共56页
OSAL解读笔记.docx_第16页
第16页 / 共56页
OSAL解读笔记.docx_第17页
第17页 / 共56页
OSAL解读笔记.docx_第18页
第18页 / 共56页
OSAL解读笔记.docx_第19页
第19页 / 共56页
OSAL解读笔记.docx_第20页
第20页 / 共56页
亲,该文档总共56页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

OSAL解读笔记.docx

《OSAL解读笔记.docx》由会员分享,可在线阅读,更多相关《OSAL解读笔记.docx(56页珍藏版)》请在冰点文库上搜索。

OSAL解读笔记.docx

OSAL解读笔记

A先粗看了一些东西

如果某一个任务的event被置位了,就处理它。

即taskEvents[idx]!

=0

而这个事件是由中断程序之类的设置的或者由某一任务设置的?

只有有events事件发生的任务才去处理。

没有事件发生的任务将跳过。

系统信息,可能会发给本任务,这个用函数:

Osal_msg_receve(simpleosal_taskID)就可以得知。

猜想:

当系统事件发生时,它会将一个全局变量中的事件数组的某一个与0x8000或运算,到底是哪一个就是我们的任务排列的序号来决定的,例如我们在本例子中有11个任务(后来我自已又加了一个)如果第2个任务要发系统信息运去,就将这个数组置为1。

程序中的这样处理的:

tasksEvents[task_id]|=event_flag;//Stufftheeventbit(s)---见osal.c中。

这个信息处理函数(带任务ID参数)它就是读这个全局变量,看这个是发给谁的。

所以它先看有没有系统事件是发给本任务的,

uint8*osal_msg_receive(uint8task_id)

{

osal_msg_hdr_t*listHdr;///队列指针,用于搜索的

osal_msg_hdr_t*prevHdr=NULL;///前一个

osal_msg_hdr_t*foundHdr=NULL;///发现的指针处

halIntState_tintState;///这个不知是干什么用的

//Holdoffinterrupts

HAL_ENTER_CRITICAL_SECTION(intState);////进入

//Pointtothetopofthequeue

listHdr=osal_qHead;////指向队列的前部

//Lookthroughthequeueforamessagethatbelongstotheaskingtask

while(listHdr!

=NULL)////只要队列不空,就一直往下走

{

if((listHdr-1)->dest_id==task_id)///事件队列中的目标ID是指向本地ID否?

{

if(foundHdr==NULL)///第一次发现消息是给自已的

{

//Savethefirstone

foundHdr=listHdr;////发现一个消息是给自已的

}

else

{

//Secondmsgfound,stoplooking又发现一个直接退出了

break;

}

}

if(foundHdr==NULL)

{

prevHdr=listHdr;///当前这个就是第一个

}

listHdr=OSAL_MSG_NEXT(listHdr);///指向下一个

}

//Istheremorethanone?

if(listHdr!

=NULL)

{

//Yes,Signalthetaskthatamessageiswaiting

osal_set_event(task_id,SYS_EVENT_MSG);

}

else

{

//Nomore如果没有消息就告诉任务,现在没有系统消息

osal_clear_event(task_id,SYS_EVENT_MSG);

}

//Didwefindamessage?

if(foundHdr!

=NULL)////将这个消息从中间抽出来让它消失掉,这时就要知道前一个

{

//Takeoutofthelinklist

osal_msg_extract(&osal_qHead,foundHdr,prevHdr);

}

//Releaseinterrupts

HAL_EXIT_CRITICAL_SECTION(intState);

return((uint8*)foundHdr);

}

B再看一下操作系统,从中断到处理的过程

现在基本理清了按键消息是如何发过来的,有点绕。

首先,在初始化中,允许了中断并配置了回调函数(这个函数在文件onBoard.c中InitBoard()调用了它):

/*InitializeKeystuff*/

OnboardKeyIntEnable=HAL_KEY_INTERRUPT_ENABLE;

//OnboardKeyIntEnable=HAL_KEY_INTERRUPT_DISABLE;

HalKeyConfig(OnboardKeyIntEnable,OnBoard_KeyCallback);---halkey.c中定义

在配置回调函数中,它初始化了两个键盘的中断允许位和上下沿等细节,将中断屏蔽位打开,且将这个中断标志位清除。

注意到它将全局变量置为有效OnboardKeyIntEnable=1而这个变量本来没什么意义的,但发现它可以用来读键盘中断位时,在区分是用中断方式来做还是用查询方式来做时用得着这个变量。

中断函数的定义有点小技巧(宏),它就是将中断矢量放到合适的位置,而且申明了这个函数。

它既是定义,也是申明。

这个在hal_mcu.h中定义了。

(Keil和IAR不一样)

但是这个配置程序中可能有点错,PICTL是用来控制上升沿或下降沿中断的,在多功能键初始化中,即P2.0处理中,它错误将P2IEN的D3位置为1,而不是将PICTL的D3位置1。

所以这个键变成了上升沿了。

当然这并不影响程序的运行。

下面我们看一下是上升沿还是下降沿。

先看一下电路图按下去时,它会产生一个上升沿,仿真器调一下看是否是上升沿时中断?

果然,在刚按下去,还没抬起来的时候,就捕获到一个中断了。

这说明这个中断是上升尚的,证明了程序的配置下降沿是没成功的,看来TI也会出点小错误。

中断响应程序中,最后调用了:

----中断函数定义在halkey.c中.

osal_start_timerEx(Hal_TaskID,HAL_KEY_EVENT,HAL_KEY_DEBOUNCE_VALUE);将生成一个按键事件。

注意到这个Hal_TaskID这个是内核ID的任务。

延时一下可抗抖动干扰?

注意到这个函数中调用了newTimer=osalAddTimer(taskID,event_id,timeout_value);

而这个加定时器这个函数,当时只是加了一个定时器,后面的事情,就是要延时一点时间后,等时间到了后再去设置它,这个终于发现了(在定时器更新中osalTimerUpdate())

当定时时间一到,就将事件发送给相应的任务ID

osal_set_event(freeTimer->task_id,freeTimer->event_flag);

所以是它将这个按键事件是发送给内核这个任务的。

注意到这里的任务ID,就是内核任务ID。

而这个事件就是按键事件。

注意到在中断程序中,并不确定按键是哪一个,它是在HalKeyPoll()中检测键的。

而这个事件的处理在什么地方呢?

它在Hal_ProcessEvent(uint8task_id,uint16events)中。

这个是一直在调用的,它是11个运行的任务之一(事实上它是第2个任务)

在这个任务中,如果发现有系统事件,它会将这个事件读出来。

没做什么事情,也不会有这样的系统事件(在我们这个程序中)

如果是按键事件,则调用HalKeyPoll()在这个函数中将检测这个键值传送到这个回调函数中。

(pHalKeyProcessFunction)(keys,HAL_KEY_STATE_NORMAL);注意到第2个参数它=0

OnBoard_KeyCallback(uint8keys,uint8state)注意到这个state=0.

而这个shift的值为多少呢?

如果不是SW6,它就是true.如果是SW6,它就是false.

shift=(OnboardKeyIntEnable==HAL_KEY_INTERRUPT_ENABLE)?

false:

((keys&HAL_KEY_SW_6)?

true:

false);---如果是单键,它为false,为5键,它就是true.

这个回调函数,调用了OnBoard_SendKeys(keys,shift)在这个函数中,它调用了:

osal_msg_send(registeredKeysTaskID,(uint8*)msgPtr);

这个注册的任务ID,就是我们在初始化中指定的任务(最后一个任务ID)。

而这个信息就含有我们的事件名,状态,键名称。

发送消息的函数调用了osal_msg_enqueue_push(destination_task,msg_ptr,FALSE)在这个函数的开始,将消息推送到消息队列中,osal_msg_enqueue(&osal_qHead,msg_ptr);最后调用了osal_set_event(destination_task,SYS_EVENT_MSG);即告诉目标任务ID,你的系统事件到了。

有一个问题是程序是如何按键去抖动的呢?

例如由于抖动,发生了N次按键中断。

难道就要加N个定时器吗?

终于后来又发现了,它在osalAddTimer(uint8task_id,uint16event_flag,uint32timeout)完美地解决了这个问题,这个问题就在这个函数中,当增加定时器时,如果发现同样的事件,同样的任务,已经有一个定时器在运行了,则我们就不会再增加定时器了,而是将这个定时器更新一下就可以了。

而如果从来没有定时器用于这个事件和这个任务(两者同时符合,则不生成一个新的定时器)

newTimer=osalFindTimer(task_id,event_flag);

if(newTimer)///如果发现了定时器已经存在了

{

//Timerisfound-updateit.///只是将这个定时时间更新一下而已。

newTimer->timeout.time32=timeout;

return(newTimer);

}

Else///如果没有这个定时器存在,就生成一个定时器

{

//NewTimer

newTimer=osal_mem_alloc(sizeof(osalTimerRec_t));///分配一段内存

以下设置定时器的参数

}

真正的键的最后处理,交给应用层了。

因为这个信息已经封装,发送到最未的一个任务了,消息中的事件就是KEY_CHANGE它的状态就是trueorfalse---这个依赖于是5键还是单个键。

它的键名就是预定义好的6个键,分别为0x01,0x02,0x04....

后面还有注意到

tasksEvents=(uint16*)osal_mem_alloc(sizeof(uint16)*tasksCnt);

分配的是一个2*事件个数的数组例如11个任务,就分配了一个22个字节的指针处。

它是一个int16的数组,每个位表示一个事件,每个任务最多有16个事件,其中的0x8000表示的是系统事件。

即最高位为1的事件。

我们还要看一下这个始终运行的任务

do{

if(tasksEvents[idx])//Taskishighestprioritythatisready.注意到这个数组。

它代表?

{

break;

}

}while(++idx

在什么地方设置这个呢?

tasksEvents[idx]

uint8osal_set_event(uint8task_id,uint16event_flag)

{

if(task_id

{

halIntState_tintState;

HAL_ENTER_CRITICAL_SECTION(intState);//Holdoffinterrupts

tasksEvents[task_id]|=event_flag;//Stufftheeventbit(s)

HAL_EXIT_CRITICAL_SECTION(intState);//Releaseinterrupts

return(SUCCESS);

}

else

{

return(INVALID_TASK);

}

}

C自已在工程中试着加任务,传事件和附加消息,还是成功了

下面,我们试着在一个工程中,加一个任务,这个任务让一个LED灯闪。

且时间到了,就给主任务发送一条自定义的消息,此消息含一个变量,这个变量每次都++的。

通过串口打印一个时间到了XX出来。

先加一个任务试试。

1.首先在任务组中增加一个函数MyTestEvent()这个在OSAL_simpleBLECentral.c中。

2.

A增加一个MyTest_Init(taskID);注意到前面一个任务必须将tasdID++;只有最后一个才不要++。

simpleBLECentral.c中,这个是初始化的调用。

B增加一个定义staticuint8MyTestTaskId;-----simpleBLECentral.c中。

Cexternuint16MyTestEvent(uint8task_id,uint16events);----这个在simpleBLECentral.h中要定义,同时要定义的还有externvoidMyTest_Init(task_id)不然编译会出警告

3.写这个初始化函数及处理函数

A初始化函数部分:

它定义在simpleBLECentral.c中

先:

HalLedSet(HAL_LED_2,HAL_LED_MODE_ON);///没什么事就让一个灯亮一下吧

#defineSTART_TEST_EVT0x01-------------启动时加个事件试一下simpleBL...h

B处理函数部分:

它定义在simpleBLECentral.c中

我们怎样来处理这件事呢?

---简单一点

这样行不行?

先在初始化中,增加一个定时器事件。

在这个任务中,在收到定时器事件后,让灯反转一下,并重新开启一个定时器事件。

这样灯就不停地反转了。

不这么做。

复杂一点,就是先调用这个函数:

osal_start_timerEx(Hal_TaskID,HAL_TEST_EVENT,HAL_KEY_DEBOUNCE_VALUE);

我们先将一个事件,发给内核任务去处理

#defineHAL_TEST_EVENT0x1000-----这个定义在hal_drivers.c中

于是,在内核中就要增加对这个事件的处理。

但是这个处理很简单

我们知道,这个HalKeyPoll()总是要在按键被调用的。

这个是有按键事件发生时才调用,所以不能将这个事件处理放在这里。

但是我们在Hal_ProcessEvent()中处理这件事情的。

于是我们将这个事件放到这里来处理,在这个函数中增加对这个的处理部分。

原来键处理是在回调函数中处理的,我们直接。

但是有一个要定义一下,就是定义一个时间到事件

#defineTIMER_ARRIVED0xC1//gxd2015/11/25

 

下面我们再总结一下这个过程。

1.初始化时,我们先给这个我们加的这个任务,即其ID号为MyTestTaskId,其运行的任务名为:

MyTestEvent的这个任务,发送一个事件:

(事件定义在simpleBLECentral.h文件中)

osal_set_event(MyTestTaskId,START_TEST_EVT);启动测试事件,因为这个任务中也没有什么其它事件,故我们就将这个事任定义为0x01我们知道它最多有16个事件。

一般来说,这个0x8000就是系统事件。

注意到每个任务都有自已怕系统事件。

系统事件不是唯一的。

2.这个任务一旦运行,马上就会收到这个事件。

在收到这个事件后,会向内核中的HAL事件处理程序发送一个延时后的事件

osal_start_timerEx(Hal_TaskID,HAL_TEST_EVENT,HAL_TIMER_DEBOUNCE_VALUE);

3.内核程序是专门处理这个事件的。

所以过一段时间,就会收到它,这个时间长度为1000。

单位是多少呢?

需进一步了解----发现它的单位是ms看函数定义中的注释中有。

4.内核事件处理程序中,会直接调用Test_Send(0,0);这个函数。

这个函数将调用:

osal_msg_send(MyTestTaskId,(uint8*)msgPtr);即给MyTestTaskId发送一个信息。

注意看到原来键中断处理却不是这样做的,它原来的方法是在中断中,给内核任务发送一个键事件,在这个键事件处理中,调用keyPoll()中将键值得到,然后调用一个回调函数---我们预定定义好的。

在这个回调函数中,调用了OnBoard_SendKeys()这个函数,在这个函数中给我们的这个任务发一个系统消息,且将消息设置了一下。

osal_msg_send(registeredKeysTaskID,(uint8*)msgPtr);

而现在的做法是直接给测试任务发一个消息。

5.于是我们的测试任务就会收到这个消息,而且是个系统消息。

收到这个系统消息后,系统消息中的事件是TIMER_ARRIVED调用这个My_TEST_ProcessOSALMsg()这个消息。

在处理这个消息过程后,将销户这个消息。

6.在销户了这个消息之后,为了让这个过程不断地进行下去,我们再给内核发送一个测试事件。

于是这个过程继续下去。

发现这个延时启动的计时器的单位为ms.故我们将这个时间定为1000。

发现加了这部分程序后,系统就死机了。

跟踪发现信息没有发送过去。

后来发现程序将事件名称写错了,拷贝时忘记改引起的,修改后好了。

串口经常少打一个回车。

而且是每打印5次就会发生这样的错误一次。

这个不知所以了?

D试着理解一下BLE协议部分,感觉有点乱

下面再继续读一下其它的代码部分

先看系统事件,它处理按键和GATT消息部分。

先看简单点的,消息处理:

消息处理就是读写部分,当读或者写指令发出后,它在交给无线部分收发后,完成后会有响应,这个响应有4种情况,读错误,写错误,读成功,写成功。

下面具体看一下这个处理:

如果没有建立连接,则直接返回,这个可理解。

如果是读响应,(读出错不在这里)或读请求则有:

uint8valueRead=pMsg->msg.readRsp.value[0];

证明这个消息中含有读的值。

这个消息格式如下:

typedefstruct

{

osal_event_hdr_thdr;//!

uint16connHandle;//!

uint8method;//!

gattMsg_tmsg;//!

}gattMsgEvent_t;

如果不是读,也不是写,而且正在忙的话,就是在做发现的事情。

例如,在接到发现从机事件时,就将这个状态改变成正在发现状态:

simpleBLEDiscState=BLE_DISC_STATE_SVC;

此时就不是闲了。

而如果有消息过来,要不就是读,要不就是写,要不就是在发现。

所在在收到了系统消息后,一个看这个消息是不是按键消息,一个看消息中附加的事件是不是GATT消息,如果是GATT消息,则进一步看是读还是写还是其它。

其它只有一种情况就是发现消息。

而这个发现消息也是因为按了UP键引发的。

最后我们还是看一下键处理,尽管这个键处理比较复杂一些。

●先看UP键。

如果没建立连接,就调用一个函数去发现从机扫描。

如果正在扫描时按下UP键,就终止扫描了。

不过除非你连接按两下UP,不然因为连接速度很快,不会出现终止扫描这种情况。

如果已经建立连接了,按UP键的话就是一次是写,一次就是读,一直按一直这样做下去。

●再看一下左键处理。

显示扫描到的设备号。

按一下换一个,直到最多8个又回来了。

●再看右键是连接更新。

这个不知在做什么,因为源代码看不到在库里。

●再看中心键,如果选择要连接的从机是空闲状态,还没有进行连接,则进行连接,如果已经是连接状态,则断开连接。

●再看DOWN键,每按一次,是读取RSSI或取消读取RSSI。

注意到扫描和连接是两件事情。

扫描只是看下面有多少从机。

而连接则是给指定的从机去连接。

连的是谁则通过左键去选。

做试验时我们只有一个从机,只买了一个。

程序还是没有看完全,还得继续努力去消化一下。

只有多花时间多去看,对代码看上去就记住得差不多的时候,这个代码也就看得差不多了。

这样下来速度是慢了点,但是比较深入一点。

我们再一次将客户机(中心)这个程序解读一遍:

先看在这个事件处理程序:

它处理三种事件,第1种是系统事件,第2种是启动事件,第3种是开始发现事件。

简单点的先看第3种。

第3种是一个开始发现事件。

我想这个开始发现事件应该是按了UP键后发出的吧。

本来也没有必要搞这么一个绕来绕去的,在按键中直接调这个函数simpleBLECentralStartDiscovery();不就行了吗?

我们看一下在什么地方触发了这个事件?

staticvoidsimpleBLECentralEventCB(gapCentralRoleEvent_t*pEvent)中调用了这个事件。

在GAP_LINK_ESTABLISHED_EVENT事件中,发调用这个

osal_start_timerEx(simpleBLETaskId,START_DISCOVERY_EVT,DEFAULT_SVC_DISCOVERY_DELAY);

照理,我们应该在UP键中会出现这个发现设备事件?

理解错了,原来这个是发现FFF0服务?

而不是发现从机。

原来是与从机建立连接后,再启动这个发现从机服务的过程,而不是扫描从机。

注意到这里发现FFF0服务的服务。

下位机如果有N个,则怎样去发现呢?

另外每个下位机它的服务都是FFF0吗?

我估计下回还要看一下同时连接3个从机的例子能从中间找点线索吧。

调用了这个发现从机服务后,还要做什么呢?

此时应该可以与服务器的特征参数通讯了吧?

只能先跟踪到这里了。

过一会再来回顾这部分的处理吧。

接下来我们看到第2种事件,就是启动事件,启动事件由这个任务的init()的。

启动事件中,也做了不少事情的,主要有:

注册了两个函数,其中一个是RSSI事件处理回调函数和一个状态处理回调函数,也就是收到一些事件后,如何处理收到的事件消息。

绑定处理函数

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2