基于OSAL的嵌入式裸机事件驱动框架——消息队列osal_msg


参考B站up主【架构分析】嵌入式祼机事件驱动框架
感谢大佬分享


消息队列
消息分为hdr和bdy,把消息的头dhr和内容bdy做了一个分离的设计

![[Pasted image 20250124135954.png]]

dhr包括指向下一个消息的指针next,len在创建消息的时候使用,dest_id即目标任务,将消息和任务进行绑定。
bdy是消息的主体,包括数据data,还有事件id。

(注:这里的event_id和任务里的event_id 是不一样的,在任务中有个属性是事件集,表示对应于这个认为的事件集合,有16位,即一个任务最多可以对应16个事件,当有事件触发时,会将事件集对应位置1,通过按位或的方式。而消息中的event_id是不寿16限值的,当消息发送时,会将对应的任务的事件集中的最高位即消息事件置1,代表有消息来了,但是消息带来的是什么事件,这个事件event_id是不用按位或进事件集里的。消息里面的事件event_id做个区分,加个MSG,如EVE_MSG_PRINTSTAT)
![[Pasted image 20250124214341.png]]

![[Pasted image 20250124214423.png]]

消息队列的使用:
我们用户操作的都是消息主体bdy
osal_msg_alloc进行消息的内存分配以及初始化
然后使用osal_msg_send将消息发送到消息队列并触发对应任务的消息事件
在任务处理函数中呢,调用消息接收API 提取消息 osal_msg_receive,将消息bdy提取出来。提取出来之后保存,但是消息占用的空间其实还是存在的,调用osal_msg_free把消息给free掉,把占用的空间给释放掉。

其他的API用不太到

osal_msg.h

#ifndef OSAL_MSG_H #define OSAL_MSG_H  
  
#include "osal.h"  
#include "osal_task.h"  
  
#define OSAL_MSG_NEXT(msg_ptr)     ((osal_msg_hdr_t *) (msg_ptr) - 1)->next  
#define OSAL_MSG_ID(msg_ptr)   ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id  
  
typedef void* osal_msg_queue_t;  
  
typedef struct  
{  
    void *next;             /* Pointer to next message in queue */  
    osal_uint16_t len;      /* Length of message */  
    task_id_t dest_id;      /* Destination task ID */  
}osal_msg_hdr_t;  
  
typedef struct  
{  
    event_id_t event_id;    /* Event ID */  
    osal_uint8_t status;    /* Status of event */  
}osal_event_hdr_t;  
  
typedef struct  
{  
    osal_event_hdr_t hdr;  
    osal_uint8_t* data;   
}osal_msg_bdy_t;  
  
osal_uint8_t *osal_msg_alloc(osal_uint16_t len);  
osal_uint8_t osal_msg_free(void *msg_ptr);  
osal_uint8_t osal_msg_send(task_id_t task_id, void *msg_ptr);  
osal_uint8_t *osal_msg_receive(task_id_t task_id);  
  
osal_event_hdr_t *osal_msg_find(task_id_t task_id, event_id_t event_id);  
osal_uint8_t osal_msg_count(task_id_t task_id, event_id_t event_id);  
  
void osal_msg_enqueue(void *msg_ptr);  
void *osal_msg_dequeue(void);  
void osal_msg_push(void *msg_ptr);  
  
  
#endif

#define OSAL_MSG_NEXT(msg_ptr)  ((osal_msg_hdr_t *) (msg_ptr) - 1)->next  
#define OSAL_MSG_ID(msg_ptr)   ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id

宏还是要结合这个消息的结构来看
![[Pasted image 20250124163437.png]]

这里的参数msg_ptr呢,其实是bdy消息主体,先把msg_ptr强转为osal_msg_hdr_t,然后 - 1,就指向了hdr,然后就可以获取hdr的 next 或者dest_id了
注:我们在应用层获取到的都是bdy这个位置的指针,用户创建的也都是消息主体bdy,或者称为消息指针msg_ptr,然后消息的头dhr中的len是在分配消息函数的时候赋值的,dest_id是在发送函数中赋值的,next是在入队函数里将消息连接起来的

osal_msg.c

osal_msg.c全部源码

/**************************************************************************************************  
  Filename:       osal_msg.c  Description:    OSAL msg definition and manipulation functions.**************************************************************************************************/  
  
/*********************************************************************  
 * INCLUDES */#include "osal_msg.h"  
#include "osal_memory.h"  
  
/*********************************************************************  
 * MACROS */  
/*********************************************************************  
 * CONSTANTS */  
/*********************************************************************  
 * TYPEDEFS */  
/*********************************************************************  
 * GLOBAL VARIABLES */  
/*********************************************************************  
 * EXTERNAL VARIABLES */  
/*********************************************************************  
 * EXTERNAL FUNCTIONS */  
/*********************************************************************  
 * LOCAL VARIABLES */static osal_msg_queue_t msg_queue_head = NULL;  
/*********************************************************************  
 * LOCAL FUNCTION PROTOTYPES */static void osal_msg_enqueue(void *msg_ptr);  
static void osal_msg_extract(void *msg_ptr,void *prev_ptr);  
/*********************************************************************  
 * FUNCTIONS *********************************************************************/  
  
/*********************************************************************  
 * @fn      osal_msg_alloc * * @brief * *    This function is called by a task to allocate a message buffer *    into which the task will encode the particular message it wishes *    to send.  This common buffer scheme is used to strictly limit the *    creation of message buffers within the system due to RAM size *    limitations on the microprocessor.   Note that all message buffers *    are a fixed size (at least initially).  The parameter len is kept *    in case a message pool with varying fixed message sizes is later *    created (for example, a pool of message buffers of size LARGE, *    MEDIUM and SMALL could be maintained and allocated based on request *    from the tasks). * * @param   uint8 len  - wanted buffer length * @return  pointer to allocated buffer or NULL if allocation failed. */osal_uint8_t *osal_msg_alloc(osal_uint16_t len)  
{  
    osal_msg_hdr_t *hdr;  
  
    if ( len == 0 )  
        return NULL;  
  
    hdr = (osal_msg_hdr_t *) osal_mem_alloc( (osal_uint16_t)(len + sizeof( osal_msg_hdr_t )) );  
    if ( hdr != NULL )  
    {  
        hdr->next = NULL;  
        hdr->len = len;  
        hdr->dest_id = SYS_TSK_INIT;  
        return (osal_uint8_t *)(hdr + 1);  
    }  
    else  
        return NULL;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_free * * @brief * *    This function is used to deallocate a message buffer. This function *    is called by a task (or processing element) after it has finished *    processing a received message. * * * @param   uint8 *msg_ptr - pointer to new message buffer * * @return  OSAL_SUCCESS, INVALID_MSG_POINTER */osal_uint8_t osal_msg_free(void *msg_ptr)  
{  
    osal_uint8_t *ptr;  
  
    if(msg_ptr == NULL || OSAL_MSG_ID(msg_ptr) != SYS_TSK_INIT){  
        return INVALID_MSG_POINTER;  
    }  
    ptr = (osal_uint8_t *)((osal_uint8_t *)msg_ptr - sizeof( osal_msg_hdr_t ));  
    osal_mem_free((void *)ptr);  
    return OSAL_SUCCESS;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_extract * * @brief * *    This function extracts and removes an OSAL message from the *    middle of an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message to be extracted * @param   void *prev_ptr  - OSAL message before msg_ptr in queue * * @return  none */static void osal_msg_extract(void *msg_ptr,void *prev_ptr)  
{  
    if (msg_ptr == msg_queue_head) {  
        msg_queue_head = OSAL_MSG_NEXT(msg_ptr);  
    }else{  
        OSAL_MSG_NEXT(prev_ptr) = OSAL_MSG_NEXT(msg_ptr);  
    }  
    OSAL_MSG_NEXT(msg_ptr) = NULL;  
    OSAL_MSG_ID(msg_ptr) = SYS_TSK_INIT;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_send * * @brief * *    This function is called by a task to send a command message to *    another task or processing element.  The sending_task field must *    refer to a valid task, since the task ID will be used *    for the response message.  This function will also set a message *    ready event in the destination tasks event list. * * * @param   uint8 destination task - Send msg to?  Task ID * @param   uint8 *msg_ptr - pointer to new message buffer * @param   uint8 len - length of data in message * * @return  SUCCESS, INVALID_TASK, INVALID_MSG_POINTER */osal_uint8_t osal_msg_send(task_id_t task_id, void *msg_ptr)  
{  
    if(msg_ptr == NULL){  
        return INVALID_MSG_POINTER;  
    }  
    if(osal_task_find(task_id) == NULL){  
        osal_msg_free(msg_ptr);  
        return INVALID_TASK;  
    }  
    if(OSAL_MSG_NEXT(msg_ptr) != NULL || OSAL_MSG_ID(msg_ptr) != SYS_TSK_INIT){  
        osal_msg_free(msg_ptr);  
        return INVALID_MSG_POINTER;  
    }  
    OSAL_MSG_ID(msg_ptr) = task_id;  
    osal_msg_enqueue(msg_ptr);  
    osal_task_seteve(task_id, SYS_EVE_MSG);  
    return OSAL_SUCCESS;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_receive * * @brief * *    This function is called by a task to retrieve a received command *    message. The calling task must deallocate the message buffer after *    processing the message using the osal_msg_deallocate() call. * * @param   uint8 task_id - receiving tasks ID * * @return  *uint8 - message information or NULL if no message */osal_uint8_t *osal_msg_receive(task_id_t task_id)  
{  
    osal_msg_hdr_t *list_hdr;            // Pointer to current message  
    osal_msg_hdr_t *prev_hdr = NULL;     // Pointer to previous message  
    osal_msg_hdr_t *found_hdr = NULL;    // Pointer to message to be extracted  
  
    // Find the first message in the queue for the given task    list_hdr = msg_queue_head;  
    while (list_hdr != NULL)  
    {  
        //compare task id  
        if((list_hdr - 1)->dest_id == task_id)  
        {  
            //If found for the first time, set found_hdr to current list_hdr  
            //if not first time, break out of loop            if(found_hdr == NULL){  
                found_hdr = list_hdr;  
            }else{  
                break;  
            }  
        }  
        //if not found, move prev_hdr to current list_hdr  
        if(found_hdr == NULL){  
            prev_hdr = list_hdr;  
        }  
        // Move to next message in queue  
        list_hdr = OSAL_MSG_NEXT(list_hdr);  
    }  
  
    // Set event for task if message found  
    if(list_hdr != NULL){  
        osal_task_seteve(task_id, SYS_EVE_MSG);  
    }else{  
        osal_task_clreve(task_id, SYS_EVE_MSG);  
    }  
  
    // Extract message from queue  
    if(found_hdr != NULL){  
        osal_msg_extract(found_hdr, prev_hdr);  
    }else{  
        return NULL;  
    }  
    // Return extracted message  
    return (osal_uint8_t *)found_hdr;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_enqueue * * @brief * *    This function enqueues an OSAL message into an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message * * @return  none */static void osal_msg_enqueue(void *msg_ptr)  
{  
    void *list;  
    OSAL_MSG_NEXT(msg_ptr) = NULL;  
  
    if (msg_queue_head == NULL) {  
        msg_queue_head = msg_ptr;  
    }else{  
        for(list = msg_queue_head; OSAL_MSG_NEXT(list) != NULL; list = OSAL_MSG_NEXT(list));  
        OSAL_MSG_NEXT(list) = msg_ptr;  
    }  
}  
  
/*********************************************************************  
 * @fn      osal_msg_dequeue * * @brief * *    This function dequeues an OSAL message from an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * * @return  void * - pointer to OSAL message or NULL of queue is empty. */void *osal_msg_dequeue(void)  
{  
    void *msg_ptr = NULL;  
  
    if (msg_queue_head != NULL) {  
        msg_ptr = msg_queue_head;  
        msg_queue_head = OSAL_MSG_NEXT(msg_ptr);  
        OSAL_MSG_NEXT(msg_ptr) = NULL;  
        OSAL_MSG_ID(msg_ptr) = SYS_TSK_INIT;  
    }  
    return msg_ptr;  
}  
  
/*********************************************************************  
 * @fn      osal_msg_push * * @brief * *    This function pushes an OSAL message to the head of an OSAL *    queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message * * @return  none */void osal_msg_push(void *msg_ptr)  
{  
    OSAL_MSG_NEXT(msg_ptr) = msg_queue_head;  
    msg_queue_head = msg_ptr;  
}  
  
/**************************************************************************************************  
 * @fn          osal_msg_find * * @brief       This function finds in place an OSAL message matching the task_id and event *              parameters. * * input parameters * * @param       task_id - The OSAL task id that the enqueued OSAL message must match. * @param       event - The OSAL event id that the enqueued OSAL message must match. * * output parameters * * None. * * @return      NULL if no match, otherwise an in place pointer to the matching OSAL message. ************************************************************************************************** */osal_event_hdr_t *osal_msg_find(task_id_t task_id, event_id_t event_id)  
{  
    osal_msg_hdr_t *header;  
    header = (osal_msg_hdr_t *)msg_queue_head;  
  
    while(header != NULL)  
    {  
        if(((header - 1)->dest_id == task_id) && (((osal_event_hdr_t *)header)->event_id == event_id)){  
            break;  
        }  
        header = OSAL_MSG_NEXT(header);  
    }  
  
    return (osal_event_hdr_t *)header;  
}  
  
osal_uint8_t osal_msg_count(task_id_t task_id, event_id_t event_id)  
{  
    osal_msg_hdr_t *header;  
    osal_uint8_t msg_cnt = 0;  
  
    header = msg_queue_head;  
  
    while(header != NULL)  
    {  
        if(((header - 1)->dest_id == task_id) && ((event_id == SYS_EVE_ANY) || (((osal_event_hdr_t *)header)->event_id == event_id))){  
            msg_cnt++;  
        }  
        header = OSAL_MSG_NEXT(header);  
    }  
    return msg_cnt;  
}

osal_msg_alloc

消息创建
msg_bdy才是消息的主体,才是我们真正想要发送的东西
传进来的参数len是msg_bdy的长度,
因为消息是有hdr+bdy一起构成的嘛,所以分配的空间长度是len + sizeof( osal_msg_hdr_t ),也就是下面这个图的长度
![[Pasted image 20250124163437.png]]

但是返回的指针是osal_msg_hdr_t,也就是指向最左边osal_msg_hdr_t
然后进行初始化,next指向NULL,dest_id现赋值一个SYS_TSK_INIT,等到发送函数中在指定任务id。返回的时候,hdr+1,就指向了hdr后面那块内存,也就是bdy的地址

/*********************************************************************  
 * @fn      osal_msg_alloc * * @brief * *    This function is called by a task to allocate a message buffer *    into which the task will encode the particular message it wishes *    to send.  This common buffer scheme is used to strictly limit the *    creation of message buffers within the system due to RAM size *    limitations on the microprocessor.   Note that all message buffers *    are a fixed size (at least initially).  The parameter len is kept *    in case a message pool with varying fixed message sizes is later *    created (for example, a pool of message buffers of size LARGE, *    MEDIUM and SMALL could be maintained and allocated based on request *    from the tasks). * * @param   uint8 len  - wanted buffer length * @return  pointer to allocated buffer or NULL if allocation failed. */osal_uint8_t *osal_msg_alloc(osal_uint16_t len)  
{  
    osal_msg_hdr_t *hdr;  
  
    if ( len == 0 )  
        return NULL;  
  
    hdr = (osal_msg_hdr_t *) osal_mem_alloc( (osal_uint16_t)(len + sizeof( osal_msg_hdr_t )) );  
    if ( hdr != NULL )  
    {  
        hdr->next = NULL;  
        hdr->len = len;  
        hdr->dest_id = SYS_TSK_INIT;  
        return (osal_uint8_t *)(hdr + 1);  
    }  
    else  
        return NULL;  
}

osal_msg_free

释放消息内存
在消息处理后要释放消息内存

如果消息bdy == NULL 是空消息
如果消息的dest_id是SYS_TSK_INIT,则没处理完(处理完的消息会将它的dest_id置为SYS_TSK_INIT)
msg_ptr指向的是bdy,先转为osal_uint8_t,一个字节8位,然后减去osal_msg_hdr_t的大小,就获取到了osal_msg_hdr_t的最开头的地址,然后释放消息内存

/*********************************************************************  
 * @fn      osal_msg_free * * @brief * *    This function is used to deallocate a message buffer. This function *    is called by a task (or processing element) after it has finished *    processing a received message. * * * @param   uint8 *msg_ptr - pointer to new message buffer * * @return  OSAL_SUCCESS, INVALID_MSG_POINTER */osal_uint8_t osal_msg_free(void *msg_ptr)  
{  
    osal_uint8_t *ptr;  
  
    if(msg_ptr == NULL || OSAL_MSG_ID(msg_ptr) != SYS_TSK_INIT){  
        return INVALID_MSG_POINTER;  
    }  
    ptr = (osal_uint8_t *)((osal_uint8_t *)msg_ptr - sizeof( osal_msg_hdr_t ));  
    osal_mem_free((void *)ptr);  
    return OSAL_SUCCESS;  
}

osal_msg_send

消息发送

  1. 赋值dest_id
  2. 将消息入队
  3. 触发对应任务的消息事件
    实际上是做了这么几个操作

首先检测
如果消息为NULL,则是无效消息
如果任务为NULL,则无效任务,将消息释放
如果消息的next!=NULL 或者消息的ID !=SYS_TSK_INIT,这是啥意思的呢?因为你这个消息msg_ptr到目前为止,还是没有入队的,也没有给它赋值dest_id,所以如果消息不满足这个条件,说明它被篡改了。

检测完消息后,赋值dest_id,入队,设置对应任务的系统消息事件

/*********************************************************************  
 * @fn      osal_msg_send * * @brief * *    This function is called by a task to send a command message to *    another task or processing element.  The sending_task field must *    refer to a valid task, since the task ID will be used *    for the response message.  This function will also set a message *    ready event in the destination tasks event list. * * * @param   uint8 destination task - Send msg to?  Task ID * @param   uint8 *msg_ptr - pointer to new message buffer * @param   uint8 len - length of data in message * * @return  SUCCESS, INVALID_TASK, INVALID_MSG_POINTER */osal_uint8_t osal_msg_send(task_id_t task_id, void *msg_ptr)  
{  
    if(msg_ptr == NULL){  
        return INVALID_MSG_POINTER;  
    }  
    if(osal_task_find(task_id) == NULL){  
        osal_msg_free(msg_ptr);  
        return INVALID_TASK;  
    }  
    if(OSAL_MSG_NEXT(msg_ptr) != NULL || OSAL_MSG_ID(msg_ptr) != SYS_TSK_INIT){  
        osal_msg_free(msg_ptr);  
        return INVALID_MSG_POINTER;  
    }  
    OSAL_MSG_ID(msg_ptr) = task_id;  
    osal_msg_enqueue(msg_ptr);  
    osal_task_seteve(task_id, SYS_EVE_MSG);  
    return OSAL_SUCCESS;  
}

osal_msg_enqueue

消息入队
从消息队列尾添加一个消息
这里才是真正的消息入队,就像把消息连接起来
遍历链表,将消息插入队尾
![[Pasted image 20250124214451.png]]

/*********************************************************************  
 * @fn      osal_msg_enqueue * * @brief * *    This function enqueues an OSAL message into an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message * * @return  none */void osal_msg_enqueue(void *msg_ptr)  
{  
    void *list;  
    OSAL_MSG_NEXT(msg_ptr) = NULL;  
  
    if (msg_queue_head == NULL) {  
        msg_queue_head = msg_ptr;  
    }else{  
        for(list = msg_queue_head; OSAL_MSG_NEXT(list) != NULL; list = OSAL_MSG_NEXT(list));  
        OSAL_MSG_NEXT(list) = msg_ptr;  
    }  
}

osal_msg_receive

消息接收函数

在消息发送函数中,调用消息入队函数,然后消息队列头msg_queue_head就会指向消息主体bdy了,而不是消息头hdr

那么这里遍历消息链表为什么将list_hdr定义为osal_msg_hdr_t呢?

首先msg_queue_head其实指向消息主体,那么由消息主体怎么获得消息头dhr呢,将消息主体强制转为osal_msg_hdr_t类型,然后在 -1 ,就得到消息头dhr了。

将list_hdr定义为osal_msg_hdr_t,就相当于省略了强转的这么一个步骤

list_hdr用于遍历消息队列
found_hdr是要提取出来的消息,且在函数最后要返回它
prev_hdr也是一直在移动的,但是它移动到哪里呢?移动到第一个found_hdr之前一个。prev_hdr的作用是将found_hdr提取出去之后,能使这个队列依然保持连接,不能扣掉一个就断了。

为什么说是第一个found_hdr呢?

因为有可能found_hdr不知一个

来依次看一下几种情况

  1. 消息队列中没有符合task_id的消息:
    list_hdr会一直遍历,知道指向NULL。调用osal_task_clreve清除消息事件
    prev_hdr指向队列最后一个消息。
    因为没有符合task_id的消息,所以found_hdr指向NULL
    返回NULL,没有消息提取出来
  2. 消息队列中只有一个符合task_id的消息msg:
    遍历队列,找到符合消息后,found_hdr 就指向msg
    prev_hdr指向msg的前一个消息
    list_hdr还是一直在遍历,直到指向NULL,然后调用osal_task_clreve清除消息事件
    osal_msg_extract会将msg提取出来,并保证队列的连接
    返回msg的地址
  3. 消息队列中存在符合task_id的消息,且不止一个(发生了消息堆积),比如msg1,msg2:
    遍历队列,找到符合消息后,found_hdr 就指向msg1
    同样prev_hdr指向msg1 的前一个消息
    list_hdr还是一直在遍历,但是又遇到了第二个msg2。看程序中如何处理的,found_hdr不指向NULL了,found_hdr 就指向msg1了,所以会break跳出循环。
    跳出循环后,这时候list_hdr指向msg2。所以会调用osal_task_seteve再次触发任务的消息事件。
    osal_msg_extract会将msg1提取出来,并保证队列的连接
    返回msg1的地址
    区别是什么呢,就是如果有多个消息,不会将消息事件位清除掉(事件集最高位),而是将其再次置位,因为有消息没处理完呀,所以会再次触发消息事件处理函数handler,然后再次调用消息接收函数osal_msg_receive,在把msg2提取出去。
/*********************************************************************  
 * @fn      osal_msg_receive * * @brief * *    This function is called by a task to retrieve a received command *    message. The calling task must deallocate the message buffer after *    processing the message using the osal_msg_deallocate() call. * * @param   uint8 task_id - receiving tasks ID * * @return  *uint8 - message information or NULL if no message */osal_uint8_t *osal_msg_receive(task_id_t task_id)  
{  
    osal_msg_hdr_t *list_hdr;            // Pointer to current message  
    osal_msg_hdr_t *prev_hdr = NULL;     // Pointer to previous message  
    osal_msg_hdr_t *found_hdr = NULL;    // Pointer to message to be extracted  
  
    // Find the first message in the queue for the given task    list_hdr = msg_queue_head;  
    while (list_hdr != NULL)  
    {  
        //compare task id   
if((list_hdr - 1)->dest_id == task_id)  
        {  
            //If found for the first time, set found_hdr to current list_hdr  
            //if not first time, break out of loop            if(found_hdr == NULL){  
                found_hdr = list_hdr;  
            }else{  
                break;  
            }  
        }  
        //if not found, move prev_hdr to current list_hdr  
        if(found_hdr == NULL){  
            prev_hdr = list_hdr;  
        }  
        // Move to next message in queue  
        list_hdr = OSAL_MSG_NEXT(list_hdr);  
    }  
  
    // Set event for task if message found  
    if(list_hdr != NULL){  
        osal_task_seteve(task_id, SYS_EVE_MSG);  
    }else{  
        osal_task_clreve(task_id, SYS_EVE_MSG);  
    }  
  
    // Extract message from queue  
    if(found_hdr != NULL){  
        osal_msg_extract(found_hdr, prev_hdr);  
    }else{  
        return NULL;  
    }  
    // Return extracted message  
    return (osal_uint8_t *)found_hdr;  
}

osal_msg_extract

消息提取函数

将消息从消息队列中提取出来,并保存队列的连接性

/*********************************************************************  
 * @fn      osal_msg_extract * * @brief * *    This function extracts and removes an OSAL message from the *    middle of an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message to be extracted * @param   void *prev_ptr  - OSAL message before msg_ptr in queue * * @return  none */static void osal_msg_extract(void *msg_ptr,void *prev_ptr)  
{  
    if (msg_ptr == msg_queue_head) {  
        msg_queue_head = OSAL_MSG_NEXT(msg_ptr);  
    }else{  
        OSAL_MSG_NEXT(prev_ptr) = OSAL_MSG_NEXT(msg_ptr);  
    }  
    OSAL_MSG_NEXT(msg_ptr) = NULL;  
    OSAL_MSG_ID(msg_ptr) = SYS_TSK_INIT;  
}

osal_msg_find

我们说过msg_queue_head,队列头其实指向的是第一个消息的dby,这里只是强转为osal_msg_hdr_t类型,是为了-1后就可以获取消息的dest_id了。
查找消息呢,还要满足事件event_id一致。
header指向的其实是消息的bdy这个地址,那么osal_event_hdr hdr呢又是osal_msg_hdr_t的第一个元素,所以这两个其实是同一个地址,直接将header强转为osal_event_hdr_t类型,就可以访问event_id了
![[Pasted image 20250124214038.png]]

![[Pasted image 20250124214542.png]]

/**************************************************************************************************  
 * @fn          osal_msg_find * * @brief       This function finds in place an OSAL message matching the task_id and event *              parameters. * * input parameters * * @param       task_id - The OSAL task id that the enqueued OSAL message must match. * @param       event - The OSAL event id that the enqueued OSAL message must match. * * output parameters * * None. * * @return      NULL if no match, otherwise an in place pointer to the matching OSAL message. ************************************************************************************************** */osal_event_hdr_t *osal_msg_find(task_id_t task_id, event_id_t event_id)  
{  
    osal_msg_hdr_t *header;  
    header = (osal_msg_hdr_t *)msg_queue_head;  
  
    while(header != NULL)  
    {  
        if(((header - 1)->dest_id == task_id) && (((osal_event_hdr_t *)header)->event_id == event_id)){  
            break;  
        }  
        header = OSAL_MSG_NEXT(header);  
    }  
  
    return (osal_event_hdr_t *)header;  
}

osal_msg_dequeue

从消息队列头提取一个消息

/*********************************************************************  
 * @fn      osal_msg_dequeue * * @brief * *    This function dequeues an OSAL message from an OSAL queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * * @return  void * - pointer to OSAL message or NULL of queue is empty. */void *osal_msg_dequeue(void)  
{  
    void *msg_ptr = NULL;  
  
    if (msg_queue_head != NULL) {  
        msg_ptr = msg_queue_head;  
        msg_queue_head = OSAL_MSG_NEXT(msg_ptr);  
        OSAL_MSG_NEXT(msg_ptr) = NULL;  
        OSAL_MSG_ID(msg_ptr) = SYS_TSK_INIT;  
    }  
    return msg_ptr;  
}

osal_msg_push

从消息队列头添加一个消息

/*********************************************************************  
 * @fn      osal_msg_push * * @brief * *    This function pushes an OSAL message to the head of an OSAL *    queue. * * @param   osal_msg_q_t *q_ptr - OSAL queue * @param   void *msg_ptr  - OSAL message * * @return  none */void osal_msg_push(void *msg_ptr)  
{  
    OSAL_MSG_NEXT(msg_ptr) = msg_queue_head;  
    msg_queue_head = msg_ptr;  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/960131.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Github 2025-01-25Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-01-25统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Python项目1Vue项目1JavaScript项目1Deno: 现代JavaScript和TypeScript运行时 创建周期:2118 天开发语言:Rust, JavaScript协议类型…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.8 随机数奥秘:生成符合现实分布的虚拟数据

1.8 随机数奥秘:生成符合现实分布的虚拟数据 目录 #mermaid-svg-wHqPAE3mMd8HNYmi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wHqPAE3mMd8HNYmi .error-icon{fill:#552222;}#mermaid-svg-wHqPAE3mM…

使用vitepress搭建自己的博客项目

一、介绍can-vitepress-blog 什么是CAN BLOG CAN BLOG是基于vitepress二开的个人博客系统,他能够方便使用者快速构建自己的博客文章,无需繁琐的配置和复杂的代码编写。 CAN BLOG以antdv为UI设计基础,简洁大方,界面友好&#xf…

STranslate 中文绿色版即时翻译/ OCR 工具 v1.3.1.120

STranslate 是一款功能强大且用户友好的翻译工具,它支持多种语言的即时翻译,提供丰富的翻译功能和便捷的使用体验。STranslate 特别适合需要频繁进行多语言交流的个人用户、商务人士和翻译工作者。 软件功能 1. 即时翻译: 文本翻译&#xff…

【数据结构】_链表经典算法OJ:合并两个有序数组

目录 1. 题目描述及链接 2. 解题思路 3. 程序 3.1 第一版 3.2 第二版 1. 题目描述及链接 题目链接:21. 合并两个有序链表 - 力扣(LeetCode) 题目描述: 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给…

51单片机开发:动态数码管

实验目标:使8个数码管依次显示01234567。 动态数码管的原理图如下图所示:两个四位一体的数码管,其段选接在P0端口上。下表以数字0为例,描述端口输出值与数码管显示的对照关系。 dpgfedcbaP07P06P05P04P03P02P01P00001111110x3f&…

84,【8】BUUCTF WEB [羊城杯 2020]Blackcat

进入靶场 音乐硬控我3分钟 回去看源码 <?php // 检查 POST 请求中是否包含 Black-Cat-Sheriff 和 One-ear 字段 // 如果任意一个字段为空&#xff0c;则输出错误信息并终止脚本执行 if(empty($_POST[Black-Cat-Sheriff]) || empty($_POST[One-ear])){die(请提供 Black-C…

挂载mount

文章目录 1.挂载的概念(1)挂载命令&#xff1a;mount -t nfs(2)-t 选项&#xff1a;指定要挂载的文件系统类型(3)-o选项 2.挂载的目的和作用(1)跨操作系统访问&#xff1a;将Windows系统内容挂载到Linux系统下(2)访问外部存储设备(3)整合不同的存储设备 3.文件系统挂载要做的事…

数据分箱 baggingboosting onehot独热编码 woe编码 sklearn的ensemble(集成学习)

目录 数据分箱就是将连续变量离散化。 bagging&boosting onehot独热编码 独热编码的结果如下&#xff1a; woe编码 WOE编码的基本原理 步骤一&#xff1a;计算WOE 步骤二&#xff1a;应用WOE WOE编码的优点 示例 数据示例 步骤一&#xff1a;计算每个类别的违约…

Jetson Xavier NX (ARM) 使用 PyTorch 安装 Open3D-ML 指南

由于 Jetson 为 ARM64 (aarch64) 的系统架构&#xff0c;所以不能用 pip install 直接安装&#xff0c;需要通过源码编译。 升级系统 JetPack 由于 Open3D-ML 目前只支持 CUDA 10.0 以及 CUDA 11.*&#xff0c;并且 JetPack 的 CUDA 开发环境只有10.2、11.4以及12.2&#xff0…

【Linux系统】进程间通信:进程池

进程池的结构图示如下&#xff1a; 一、初始化进程池 1、创建多个子进程 通过 main 命令行参数获取需要创建子进程的个数 判断 argc 个数&#xff0c;使用 usage 提示 在编程和命令行工具中&#xff0c;“usage” 通常指的是命令或程序的使用说明&#xff0c;即如何正确使用该…

【问题解决】el-upload数据上传成功后不显示成功icon

el-upload数据上传成功后不显示成功icon 原因 由于后端返回数据与要求形式不符&#xff0c;使用el-upload默认方法调用onSuccess钩子失败&#xff0c;上传文件的状态并未发生改变&#xff0c;因此数据上传成功后并未显示成功的icon标志。 解决方法 点击按钮&#xff0c;调用…

怎样在PPT中启用演讲者视图功能?

怎样在PPT中启用演讲者视图功能&#xff1f; 如果你曾经参加过重要的会议或者演讲&#xff0c;你就会知道&#xff0c;演讲者视图&#xff08;Presenter View&#xff09;对PPT展示至关重要。它不仅能帮助演讲者更好地掌控演讲节奏&#xff0c;还能提供额外的提示和支持&#…

【2025年数学建模美赛F题】(顶刊论文绘图)模型代码+论文

全球网络犯罪与网络安全政策的多维度分析及效能评估 摘要1 Introduction1.1 Problem Background1.2Restatement of the Problem1.3 Literature Review1.4 Our Work 2 Assumptions and Justifications数据完整性与可靠性假设&#xff1a;法律政策独立性假设&#xff1a;人口统计…

MapReduce,Yarn,Spark理解与执行流程

MapReduce的API理解 Mapper 如果是单词计数&#xff1a;hello&#xff1a;1&#xff0c; hello&#xff1a;1&#xff0c; world&#xff1a;1 public void map(Object key, // 首字符偏移量Text value, // 文件的一行内容Context context) // Mapper端的上下文&#xff0c;…

如何让Dev-C++支持C++11及以上标准

目录 问题描述解决方案步骤1&#xff1a;打开编译选项 问题描述 在Dev-C中使用C11/17/20新特性&#xff08;如pop_back()等&#xff09;时&#xff0c;可能出现编译错误&#xff1a; #include <iostream> #include<string> using namespace std; int main() {str…

springBoot 整合ModBus TCP

ModBus是什么&#xff1a; ModBus是一种串行通信协议&#xff0c;主要用于从仪器和控制设备传输信号到主控制器或数据采集系统&#xff0c;例如用于测量温度和湿度并将结果传输到计算机的系统。&#xff08;百度答案&#xff09; ModBus 有些什么东西&#xff1a; ModBus其分…

linux常用加固方式

目录 一.系统加固 二.ssh加固 三.换个隐蔽的端口 四.防火墙配置 五.用户权限管理 六.暴力破解防护 七.病毒防护 八.磁盘加密 九.双因素认证2FA 十.日志监控 十一.精简服务 一.系统加固 第一步&#xff1a;打好系统补丁 sudo apt update && sudo apt upgra…

const的用法

文章目录 一、C和C中const修饰变量的区别二、const和一级指针的结合const修饰的量常出现的错误是:const和一级指针的结合总结&#xff1a;const和指针的类型转换公式 三、const和二级指针的结合 一、C和C中const修饰变量的区别 C中&#xff1a;const必须初始化&#xff0c;叫常…

Arduino大师练成手册 -- 控制 MH-SD 卡模块

要在 Arduino 上控制 MH-SD 卡模块&#xff0c;你可以按照以下步骤进行&#xff1a; 硬件连接 VCC&#xff1a;连接到 Arduino 的 3.3V 或 5V 引脚&#xff08;根据模块的要求&#xff09;。 GND&#xff1a;连接到 Arduino 的 GND 引脚。 CS&#xff1a;连接到 Arduino 的…