开发者学堂课程【嵌入式之 RFID 开发与应用2020版:OSAL 消息收发过程】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/665/detail/11130
OSAL 消息收发过程
知道 OSAL 系统总的调度原理,接下来有一个非常常用的一个手段或者说是一个功能,就是某个进程之间某个任务之间,A 任务要给 B 任务发一个消息,这个消息的收发的过程是怎样的?
首先发送这个消息本质上是通过 osal set 去设置这个事件,提供了 osal msg send message send,仔细去分析这个源代码,想了解的哪个地方可以直接去搜索。
以这个串口为例,串口在接收到数据的他把接收到的串口的数据,把它放到了 msg里面,PMSG 然后再加一个 msg,这里 OSAL 申请的空间给了 pmsg,之后就调用了 osal send message 去发送,那这个地方有个任务 ID,也就是说要把这个消息发给哪一个任务,这个就是他的 ID 也就是刚才第一个任务,ID;第二个是发的内容。
j++;
〃记录字符数
flag=1;
〃己经从串口接收到信息
}
if(flag==1)
〃已经从串口接收到信息
{
/* Allocate memory for the data */
//分配内存空间,为机构体内容+数据内容+1个记录长度的数据 pMsg
=
(mtOSALSerialData_t *)osal_msg|_allocate( sizeof
(mtOSALSerialData_t )+j+3);
//事件号用原来的 cmd_serial[msg
pAfsg->hdr.event = CMD_SERIAL_MSG;
pMsg->msg
= (uint8*)(pMsg+l);
//把数据定位到结构体数据部分
pMsg
-
>msg [θ]= port;
//给上层的数据第一个是串口号
pMsg->msg
[1]= j;
//给上层的数握第二个是长度
buf[j] =
0;
strcpy((char *)&(pMsg->msg[2]),(const char *)buf);
// for(i=θ;i<j;i++)
〃从第二个开始记录数据
// pMsg->msg [i+2]= buf[i];
osal_msg_send(
my_TaskID,
(byte
*)pMsg );
〃登记任务,发往上层
/* deallocate the msg */
// osal_msg_deallocate ( (uint8 *)pMsg );
〃释放内存
}
}« end MT_UartProcessZToolData »
#else
msg 消息发送过程:
osal _ msg _ send (uint8 taskID , void msg _ ptr )
msg _ ptr 指向消息内容,不能为空
放入消息队列 osal _ msg _ enqueue (& osal _ qHead , msg _ ptr );
最后通过 osal _ set _ event ( taskID , SYS _ EVENT _ MSG )
给任务事件置位
msg 消息接收过程:
msg _ ptr = osal _ msg _ receive ( taskID );>
消息队列取出
osal _ msg _ extract (& osal _ qHead , msg _ ptr ,
清除事件 osal _ clear _ event ( taskID , SYS_EVENT-MSG)
具体的发送的过程会把它放到队列当中去。然后通过最后你看。
Osal set event 可以到这个里面去进去看一下。
}
// Check the message header
if ( OSAL_MSG_NEXT( msg_ptr ) != NULL || OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK ) {
osal_msg_deallocate( msg_ptr ); return
( INVALID_MSG_POINTER );
}
OSAL_MSG_ID( msg_ptr ) = destination_task;
// queue message
osal_msg_enqueue(
&osal_qHsad,
msg_ptr );
// Signal the task that a message is waiting os[al_set_event ( destination_task, SYS_EVENT_MSG );
return ( SUCCESS );
} « end osal_msg_send »
*
@fn osal_msg_receive
*
* @brief
这个事件的类型就是叫做 SYS_EVENT_MSG 然后这个消息发出去了,对方去接收让的第一步,并不是去搜这个消息,而是去搜这个事件。
//任务事件处理函数
uintl6 my_ProcessEvent( uint8 task_id, uintl6 events )
{
afIncomingMSGPacket_t *MSGpkt = NULL;
ifevents & SYS_EVENT_MSG)
{
MSGpkt = (aflncomingMSGPacket t *)osal msg receive( my TaskID );
while(MSGpkt != NULL){
switch ( MSGpkt->hdr.event )
{
case ZDO_STATE_CHANGE:
identity_nwk = (devStates_t)(MSGpkt->hdr.status);
if(identity_nwk == DEV_END_DEVICE){
debug("入'网成功\n");
debug("获得地址=0x%x\n",NLME_GetShortAddr());
#if CTRL_0R GATHER
// 控制节点/采集节点入网成功后尧发一个数据给协调器以确认自己是谁,
send_coord_affirm(SAMPLEAPP_CTRL_CLUSTERID);//这是不同终端要改
#else
send_coord_affirm(SAMPLEAPP_SENSOR_CLUSTERID);
//这是不同终端要改
只要被调度,就要去判断有没有发生这个事件,被调度的是因为有人给他调用了osal set event 他才会被调用。他被调用的第一步就检测有没有收到这个消息,如果if是成立的就表示收到这个消息之后再调用 osal msg receive 这个函数去接收消息。可以看到它首先调用这个函数从消息队列里面把消息提取出来,最后清除这个任务。
消息收发操作流程:
申请消息空间(消息开头都会有 osal _ msg _ hdr _ t 结构): msgstr = osal _ m $ g _ allocate (1en)
消息内容的初始化: strcpy ( msgstr ,” helloln ");>
发送消息: osal _ msg _ send ( xxTaskID , msgstr )- osal _ msg _ enqueue
(在链表结尾添加节点
接收消息(根据任务 ID 进行接收): msg = osal _ msg _ receive ( xx _ TaskID )
对得到的消息进行处理
释放消息: osal _ msg _ deallocate O()
这里也有他的详细过程,申请,空间,拷贝,接收完了以后还要释放,这个地方接收是在这个里面。这个消息调用了操作系统,这个 osal_ msg_ ollocate, 释放必须要调的 deallocate,这就有点像 C 语言里面的那个 Malloc 和 Free,但他释放的对象是谁得去看它在发送的时候 Allocation 给了谁,他给的 pmsg。相当于他的这个返回值。
再去找有没有地方调用 deallocate 也就是前面这些接收到消息之后,这里都是使用。当使用完不再使用的时候,就必须要调用这个就把
把它释放掉。这个就是整个消息的收发流程,在操作系统里面这个任务之间通信也是时常发生的,所以这个过程一定要搞清楚,而且一定要理解消息收发的本质是什么。
本质其实就是往消息队列里面放了一块申请的空间,并且通过之前那个事件的机制去把某个事件给置位,让操作系统在轮询调度的过程当中能够发现这个事件从而去调度相应的任务去处理这个消息。