基于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;  
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于MySQL InnoDB存储引擎的一些认识

文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的?1.1 MySQL的存储引擎有哪些?1.2 MyIsam和InnoDB有什么区别? 2.MySQL表的结构是什么?2.1 行结构是什么样呢?2.1.1 NULL列表?2.1.2 char和varc…

单相可控整流电路——单相桥式全控整流电路

以下是关于单相桥式整流电路的介绍: 电路构成(带阻性负载的工作情况) - 二极管:是电路0的核心元件,通常采用四个同型号或根据需求选择不同型号的二极管,如1N4001、1N4007等,如图Vt1和Vt4是一对…

Linux(Centos、Ubuntu) 系统安装jenkins服务

该文章手把手演示在Linux系统下如何安装jenkins服务、并自定义jenkins数据文件位置、以及jenkins如何设置国内镜像源加速,解决插件下载失败问题 安装方式:war包安装 阿里云提供的war下载源地址:https://mirrors.aliyun.com/jenkins/war/?s…

力扣算法题——11.盛最多水的容器

目录 💕1.题目 💕2.解析思路 本题思路总览 借助双指针探索规律 从规律到代码实现的转化 双指针的具体实现 代码整体流程 💕3.代码实现 💕4.完结 二十七步也能走完逆流河吗 💕1.题目 💕2.解析思路…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】 1.3 广播机制:维度自动扩展的黑魔法

1.3 《广播机制:维度自动扩展的黑魔法》 前言 NumPy 的广播机制是 Python 科学计算中最强大的工具之一,它允许不同形状的数组进行运算,而无需显式地扩展数组的维度。这一机制在实际编程中非常有用,但初学者往往对其感到困惑。在…

Semantic Kernel - Kernel理解

目录 一、关于Kernel 二、案例实战 三、运行截图 一、关于Kernel 微软的 Semantic Kernel 项目中,Semantic Kernel 是一个工具框架,旨在使得开发人员能够更容易地将大语言模型(如GPT)集成到不同的应用中。它通过提供一组接口、任务模板和集成模块,使开发者能够轻松地设计…

【MySQL】--- 复合查询 内外连接

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: MySQL 🏠 基本查询回顾 假设有以下表结构: 查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为…

Qt Designer and Python: Build Your GUI

1.install pyside6 2.pyside6-designer.exe 发送到桌面快捷方式 在Python安装的所在 Scripts 文件夹下找到此文件。如C:\Program Files\Python312\Scripts 3. 打开pyside6-designer 设计UI 4.保存为simple.ui 文件,再转成py文件 用代码执行 pyside6-uic.exe simpl…

openlayer getLayerById 根据id获取layer图层

背景: 在项目中使用getLayerById获取图层,这个getLayerById()方法不是openlayer官方文档自带的,而是自己封装的一个方法,这个封装的方法的思路是:遍历所有的layer,根据唯一标识【可能是id,也可能…

Qt 控件与布局管理

1. Qt 控件的父子继承关系 在 Qt 中,继承自 QWidget 的类,通常会在构造函数中接收一个 parent 参数。 这个参数用于指定当前空间的父控件,从而建立控件间的父子关系。 当一个控件被设置为另一控件的子控件时,它会自动成为该父控…

SOME/IP--协议英文原文讲解1

前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 一、SOM…

Ansible自动化运维实战--script、unarchive和shell模块(6/8)

文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件,其提供了一…

【模型】RNN模型详解

1. 模型架构 RNN(Recurrent Neural Network)是一种具有循环结构的神经网络,它能够处理序列数据。与传统的前馈神经网络不同,RNN通过将当前时刻的输出与前一时刻的状态(或隐藏层)作为输入传递到下一个时刻&…

《FreqMamba: 从频率角度审视图像去雨问题》学习笔记

paper:FreqMamba: Viewing Mamba from a Frequency Perspective for Image Deraining GitHub:GitHub - aSleepyTree/FreqMamba 目录 摘要 1、介绍 2、相关工作 2.1 图像去雨 2.2 频率分析 2.3 状态空间模型 3、方法 3.1 动机 3.2 预备知识 3…

iic、spi以及uart

何为总线? 连接多个部件的信息传输线,是部件共享的传输介质 总线的作用? 实现数据传输,即模块之间的通信 总线如何分类? 根据总线连接的外设属于内部外设还是外部外设将总线可以分为片内总线和片外总线 可分为数…

Android WebView 中网页被劫持的原因及解决方案

文章目录 一、原因分析二、解决方案一览三、解决方案代码案例3.1 使用 HTTPS3.2 验证 URL3.3 禁用 JavaScript3.4 使用安全的 WebView 设置3.5 监控网络请求3.6 使用安全的 DNS 四、案例深入分析4.1 问题4.2 分析 五、结论 在 Android 应用开发中,WebView 是一个常用…

Linux——网络(udp)

文章目录 目录 文章目录 前言 一、upd函数及接口介绍 1. 创建套接字 - socket 函数 2. 绑定地址和端口 - bind 函数 3. 发送数据 - sendto 函数 4. 接收数据 - recvfrom 函数 5. 关闭套接字 - close 函数 二、代码示例 1.服务端 2.客户端 总结 前言 Linux——网络基础&#xf…

C语言学习强化

前言 数据的逻辑结构包括: 常见数据结构: 线性结构:数组、链表、队列、栈 树形结构:树、堆 图形结构:图 一、链表 链表是物理位置不连续,逻辑位置连续 链表的特点: 1.链表没有固定的长度…

【ArcGIS微课1000例】0141:提取多波段影像中的单个波段

文章目录 一、波段提取函数二、加载单波段导出问题描述:如下图所示,img格式的时序NDVI数据有24个波段。现在需要提取某一个波段,该怎样操作? 一、波段提取函数 首先加载多波段数据。点击【窗口】→【影像分析】。 选择需要处理的多波段影像,点击下方的【添加函数】。 在多…

css3 svg制作404页面动画效果HTML源码

源码介绍 css3 svg制作404页面动画效果HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果 效果预览 源码如下 <!doctype html> <html> <head> <meta charse…