概述
转载请注明出处,尊重原创;
本文基于蓝牙1.3.2版本
总述:
消息处理机制流程
OSAL中实现对消息管理的功能实现是在osal.c 与 osal.h 文件中,对于操作系统来说,不可缺少的就是任务之间信息的传递,消息包括:信号量,互斥量,消息邮箱、消息队列等。在OSAL中仅仅实现了消息队列的功能,系统可以发送或接收消息,并对消息进行管理。
背景知识:在OSAL.H文件中
1、定义消息管理的消息首部,所有的消息构成都有它这部分;
typedef struct
{ //用于消息首部
void *next;
uint16 len;
uint8 dest_id;
} osal_msg_hdr_t;
其中next指针将消息组织成有序的链表,len为消息的长度,dest_id是目标任务id。
2、定义管理消息队列的指针类型,从这里也可以看出管理消息队列指针类型是空指针,也说明了消息结构的类型是变化的,不是固定的。
typedef void * osal_msg_q_t;
3、定义几个消息操作的宏
获得下一个消息
#define OSAL_MSG_NEXT(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->next
获得一个消息的消息长度
#define OSAL_MSG_LEN(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->len
获得消息发送的目标任务
#define OSAL_MSG_ID(msg_ptr) ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id
下面几个 *(q_ptr)计算,说明必须传过来的是消息链表头指针的地址,
typedef void *osal_msg_q_t;
osal_msg_q_t osal_qHead;//定义的消息头指针
//调用入队列函数osal_msg_enqueue( &osal_qHead, msg_ptr );
//它的定义处是void osal_msg_enqueue( osal_msg_q_t *q_ptr, void *msg_ptr ),这里说明q_ptr是一个二级指针。
初始化一个消息队列,将消息头指针置空
#define OSAL_MSG_Q_INIT(q_ptr) *(q_ptr) = NULL
判断消息队列是否为空
#define OSAL_MSG_Q_EMPTY(q_ptr) (*(q_ptr) == NULL)
获得消息队列头指针
#define OSAL_MSG_Q_HEAD(q_ptr) (*(q_ptr))
4、定义一个管理消息队列的变量用于管理消息队列
osal_msg_q_t osal_qHead;
从这个图可以看出osa_qHead是指向消息空间的,但是因为消息空间不能给出一个固定的结构模式,所以他是一个空指针的形式。
API函数
1、创建消息
osal_msg_allocate() 给消息分配内存空间,该函数由发送消息的任务调用以创建一个消息
参数:
len-消息的长度
1、分配内存空间(消息管理首部大小+消息的长度)
hdr=(osal_msg_hdr_t*)osal_mem_alloc((short)(len+sizeof( osal_msg_hdr_t )) );
2、填充消息首部
{
hdr->next = NULL;
hdr->len = len;
hdr->dest_id = TASK_NO_TASK;
return ( (uint8 *) (hdr + 1) );//这里返回的是消息信息空间的地址
}
创建一个消息缓冲区后,下一步是在调用函数里填充消息信息空间了。然后调用osal_msg_send()函数将一个消息发送到消息队列队末尾。
2、发送消息
osal_msg_send()函数是向消息队列发送一个消息,同时还会向目标任务的事件列表里置位消息事件。
参数:
destination_task:目标任务id
*msg_ptr: 指向消息空间
uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )
{
return ( osal_msg_enqueue_push( destination_task, msg_ptr, FALSE ) );
}
//他是调用了一个入队列函数,最后参赛FALSE是指明入队列末尾。也就是说发送消息只是入队列而已
3、将消息入队列
osal_msg_enqueue_push( uint8 destination_task, uint8 *msg_ptr, uint8 push )函数功能是将一则消息入消息队列,同时设置目的任务的消息事件。
参数:
destination_task:目标任务id
*msg_ptr: 指向消息空间
push 指定是入队头还是队尾;TRUE是对头,FALSE是队尾
主要函数代码:
OSAL_MSG_ID( msg_ptr ) = destination_task;//将目标id复制给消息头dest_id
if ( push == TRUE )
{
// prepend the message如果push为TRUE则将消息插入到队列头部
//这样说明osal_msg_push函数是仅仅将消息插入队列头部
osal_msg_push( &osal_qHead, msg_ptr );
}
else
{
// append the message这里就是将消息插入队列尾部
osal_msg_enqueue( &osal_qHead, msg_ptr );
}
// Signal the task that a message is waiting置位相应任务的消息事件
osal_set_event( destination_task, SYS_EVENT_MSG );
对入队列调用的API讲解
osal_msg_push( &osal_qHead, msg_ptr );
将消息插入到队列对头,当push为TRUE时候执行。&osal_qHead是队列头指针的地址,msg_ptr是指向消息空间的指针
osal_msg_enqueue( &osal_qHead, msg_ptr );
将消息插入到队列末尾,&osal_qHead是队列头指针的地址,msg_ptr是指向消息空间的指针。
4发送消息的另外一种方式
osal_msg_push_front方式
uint8 osal_msg_push_front( uint8 destination_task, uint8 *msg_ptr )
{
return ( osal_msg_enqueue_push( destination_task, msg_ptr, TRUE ) );//最后一个参数TRUE表明插入到队列头
}
它与osal_msg_send唯一不同的是它将消息插入到队列头
5以上完成了一个消息的创建,发送,入队列的过程。下面就是任务消息事件的处理了。
6目标任务执行处理系统消息事件
1、获取该任务的消息uint8 *osal_msg_receive( uint8 task_id )
osal_msg_hdr_t *listHdr; //定义用来遍历消息队列,指向当前遍历的元素
osal_msg_hdr_t *prevHdr = NULL; //用来遍历时候使用,指向foundHdr指针前一个元素
osal_msg_hdr_t *foundHdr = NULL; //指向发现符合该任务的消息
halIntState_t intState;
// Hold off interrupts
HAL_ENTER_CRITICAL_SECTION(intState);
// Point to the top of the queue osal_qHead指向的是消息信息结构体,不是消息头结构体
listHdr = osal_qHead;
// Look through the queue for a message that belongs to the asking task
while ( listHdr != NULL )
{
if ( (listHdr - 1)->dest_id == task_id )
{//找到了该任务的消息
if ( foundHdr == NULL )
{
// Save the first one
foundHdr = listHdr;
}
else
{//如果有两个,则调出循环下次在执行
// Second msg found, stop looking
break;
}
}
//若没找到符合的消息,那么prevHdr向下遍历,如果找到了,foundHdr不为0,prevHdr不再往下遍历了,指向foundHdr前一个元素
if ( foundHdr == NULL )
{
prevHdr = listHdr;
}
listHdr = OSAL_MSG_NEXT( listHdr );
}
该段代码主要是在消息队列中寻找目标任务的消息;跳出这个while循环有两种情况,1、找到了消息,同时listHdr也到了队列末尾,那么是因为while条件不满足listHdr = NULL而结束循环;2、找到了消息但是是通过break结束while循环,那么说明该任务不止一个消息,OSAL在这里的处理方式是先处理完这个事件,然后在过来处理下一个该任务的消息事件。基于这两种情况,马上就有下面的处理代码了。
// Is there more than one?
if ( listHdr != NULL )
{
// Yes, Signal the task that a message is waiting如果该任务不止一个消息事件
osal_set_event( task_id, SYS_EVENT_MSG );
}
else
{
// No more,listHdr遍历到链表末尾了那么就只有一个这个任务的事件
osal_clear_event( task_id, SYS_EVENT_MSG );
}
基于上面第一段代码,找到了该任务的消息,那么下一步就是提取这个消息,本质上在数据结构里处理方式来说就是在单链表里删除一个元素,同时返回指向该消息的指针。
if ( foundHdr != NULL )
{
// Take out of the link list
osal_msg_extract( &osal_qHead, foundHdr, prevHdr );
}
// Release interrupts
HAL_EXIT_CRITICAL_SECTION(intState);
return ( (uint8*) foundHdr );
osal_msg_extract( osal_msg_q_t *q_ptr, void *msg_ptr, void *prev_ptr )接口
主要完成的功能是将一个消息从消息队列中删除,所以函数里面主要处理的是对后继指针的操作,
参数:
q_ptr指向队列头指针
msg_ptr指向待提取的消息
prev_ptr 指向待提取消息前一个元素
if ( msg_ptr == *q_ptr )
{
// remove from first待取的消息是队列第一个元素
*q_ptr = OSAL_MSG_NEXT( msg_ptr );
}
else
{
// remove from middle
OSAL_MSG_NEXT( prev_ptr ) = OSAL_MSG_NEXT( msg_ptr );
}
//下面语句的意思是将提取的消息设为无效
OSAL_MSG_NEXT( msg_ptr ) = NULL;
OSAL_MSG_ID( msg_ptr ) = TASK_NO_TASK;//将抽取的消息设为不为任务占用,等待取消消息空间
从队列中间删除一个元素的过程如图
2提取消息空间后就是调用消息处理函数
3处理完之后就是删除消息空间
osal_msg_deallocate( uint8 *msg_ptr )
//这里就是将消息空间以及消息头都包括在内
x = (uint8 *)((uint8 *)msg_ptr - sizeof( osal_msg_hdr_t ));
//释放消息空间+消息头部空间
osal_mem_free( (void *)x );
上面这些完成了一个消息从创建到发送,目标任务获取消息,处理消息,释放消息空间整个详细介绍过程。
下面介绍消息处理的其他API函数
1 osal_msg_dequeue( osal_msg_q_t *q_ptr )
函数功能是将一个消息出列。
参数:q_ptr指向一个消息结构体的指针
if ( *q_ptr != NULL )
{
// Dequeue message
msg_ptr = *q_ptr;
*q_ptr = OSAL_MSG_NEXT( msg_ptr );
OSAL_MSG_NEXT( msg_ptr ) = NULL;
OSAL_MSG_ID( msg_ptr ) = TASK_NO_TASK;
}
return msg_ptr;//返回的指向该消息结构体的指针
2 osal_msg_find(uint8 task_id, uint8 event)
函数实现的功能是根据task_id, event寻找满足这两个条件的消息
pHdr = osal_qHead; // Point to the top of the queue.
// Look through the queue for a message that matches the task_id and event parameters.
while (pHdr != NULL)
{
if (((pHdr-1)->dest_id == task_id) && (((osal_event_hdr_t *)pHdr)->event == event))
{
break;
}
pHdr = OSAL_MSG_NEXT(pHdr);
}
return (osal_event_hdr_t *)pHdr;
最后
以上就是迅速小蘑菇为你收集整理的OSAL之消息管理转载请注明出处,尊重原创;本文基于蓝牙1.3.2版本总述:背景知识:在OSAL.H文件中API函数上面这些完成了一个消息从创建到发送,目标任务获取消息,处理消息,释放消息空间整个详细介绍过程。下面介绍消息处理的其他API函数的全部内容,希望文章能够帮你解决OSAL之消息管理转载请注明出处,尊重原创;本文基于蓝牙1.3.2版本总述:背景知识:在OSAL.H文件中API函数上面这些完成了一个消息从创建到发送,目标任务获取消息,处理消息,释放消息空间整个详细介绍过程。下面介绍消息处理的其他API函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复