消息处理函数_crra效用函数

(4) 2024-05-31 14:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说消息处理函数_crra效用函数,希望能够帮助你!!!。

    重要的数据结构

typedef struct
{
  void   *next;                                     /*  指向消息队列的下一个节点    */
  uint16 len;                                       /*  消息实际内容的大小          */
  uint8  dest_id;                                   /*  指向任务的ID                */
} osal_msg_hdr_t;

typedef struct
{
  uint8  event;                                     /*  事件                        */
  uint8  status;                                    /*  状态                        */
} osal_event_hdr_t;

typedef void * osal_msg_q_t;

这里有一点要说明的是:osal_msg_q_t这个指针指向的是消息的的实际内容,即 函数osal_msg_allocate 开辟内存的返回值

还有就是                            *next 同样是指向       消息的的实际内容,即 函数osal_msg_allocate 开辟内存的返回值


这里上一张在百度文库里看到的一片文章里的关于消息数据链表的示意图

消息处理函数_crra效用函数_https://bianchenghao6.com/blog__第1张

/*********************************************************************
 * @fn      osal_msg_allocate
 *
 * @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
 *
 *          返回指向分配的消息实际内容缓冲区的指针或者如果分配失败指向NULL
 * @return  pointer to allocated buffer or NULL if allocation failed.
 */
uint8 * osal_msg_allocate( uint16 len )
{
  osal_msg_hdr_t *hdr;                      

  if ( len == 0 )
    return ( NULL );
  /*  分配一块 Len(消息实际内容缓冲区大小) + 消息头结构大小(结构体大小) 长度内存    */
  hdr = (osal_msg_hdr_t *) osal_mem_alloc( (short)(len + sizeof( osal_msg_hdr_t )) );
  /*  获取内存成功,初始化结构体   */
  if ( hdr )
  {
    hdr->next = NULL;
    hdr->len = len;
    hdr->dest_id = TASK_NO_TASK;
    return ( (uint8 *) (hdr + 1) );     /*  指向分配的消息实际内容缓冲区的指针      */
  }
  else
    return ( NULL );
}

/*********************************************************************
 * @fn      osal_msg_deallocate
 *
 * @brief
 *    当消息实际内容缓冲区不为空但是消息头ID为空时,释放已经分配的内存(消息实际内容缓冲区)
 *    这个函数往往使用在任务调用接收消息函数后对释放整条消息占用内存
 *    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  SUCCESS, INVALID_MSG_POINTER
 */
uint8 osal_msg_deallocate( uint8 *msg_ptr )
{
  uint8 *x;
    
  /*  假如消息实际内容缓冲区为NULL,返回无效的消息指针  */
  if ( msg_ptr == NULL )
    return ( INVALID_MSG_POINTER );

  /*  假如消息头的ID不为空,不释放消息内容缓冲区 
      因为上一句已经判断消息的内容缓冲区是有效的,加上消息头的ID不为空
      所以认为这条消息是有效的  
   */
  // don't deallocate queued buffer
  if ( OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
    return ( MSG_BUFFER_NOT_AVAIL );
  
  /*  假如消息头的ID为TASK_NO_TASK(指向的任务无效,消息是无效的)则清消息  */
  x = (uint8 *)((uint8 *)msg_ptr - sizeof( osal_msg_hdr_t ));

  /*  释放整条消息占用内存  */
  osal_mem_free( (void *)x );

  return ( SUCCESS );
}

/*********************************************************************
 * @fn      osal_msg_send
 *
 * @brief
 *    发送消息
 *    FALSE 表示消息插入对尾
 *    TRUE  表示消息插入对首
 *    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
 *
 * @return  SUCCESS, INVALID_TASK, INVALID_MSG_POINTER
 */
uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )
{
  return ( osal_msg_enqueue_push( destination_task, msg_ptr, FALSE ) );
}

/*********************************************************************
 * @fn      osal_msg_push_front
 *
 * @brief
 *
 *    This function is called by a task to push a command message
 *    to the head of the OSAL queue. The destination_task field
 *    must refer to a valid task, since the task ID will be used to
 *    send the message to. This function will also set a message
 *    ready event in the destination task's event list.
 *
 * @param   uint8 destination_task - Send msg to Task ID
 * @param   uint8 *msg_ptr - pointer to message buffer
 *
 * @return  SUCCESS, INVALID_TASK, INVALID_MSG_POINTER
 */
uint8 osal_msg_push_front( uint8 destination_task, uint8 *msg_ptr )
{
  return ( osal_msg_enqueue_push( destination_task, msg_ptr, TRUE ) );
}

/*********************************************************************
 * @fn      osal_msg_enqueue_push
 *
 * @brief
 *    把消息插入消息队列
 *    This function is called by a task to either enqueue (append to
 *    queue) or push (prepend to queue) a command message to the OSAL
 *    queue. The destination_task field must refer to a valid task,
 *    since the task ID will be used to send the message to. This 
 *    function will also set a message ready event in the destination
 *    task's event list.
 *
 * @param   uint8 destination_task - Send msg to Task ID
 * @param   uint8 *msg_ptr - pointer to message buffer
 * @param   uint8 push - TRUE to push, otherwise enqueue
 *
 * @return  SUCCESS, INVALID_TASK, INVALID_MSG_POINTER
 */

static uint8 osal_msg_enqueue_push( uint8 destination_task, uint8 *msg_ptr, uint8 push )
{
  if ( msg_ptr == NULL )
  {
    return ( INVALID_MSG_POINTER );
  }
  
  /*  释放消息内存  */
  if ( destination_task >= tasksCnt )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_TASK );
  }

  /*  检查消息头,假如两个条件都不满足说明该消息该消息还没有分配给任务  */
  // 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;

  if ( push == TRUE )
  {
    /*  插入队首  */
    // prepend the message
    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 );

  return ( 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
 */
uint8 *osal_msg_receive( uint8 task_id )
{
  osal_msg_hdr_t *listHdr;
  osal_msg_hdr_t *prevHdr = NULL;
  osal_msg_hdr_t *foundHdr = NULL;
  halIntState_t   intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);                         /*  关中断                          */

  // Point to the top of the queue
  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 )                    /*  假如找到任务ID                  */   
    {
      if ( foundHdr == NULL )                                   /*  假如第一次找到任务ID            */   
      { 
        // Save the first one
        foundHdr = listHdr;                                     /*  保存第一个任务指针              */
      } 
      else
      {
        // Second msg found, stop looking                       /*  假如第二次找到任务ID,退出循环  */
        break;
      }
    } 
    /*  假如当前节点不是要找到任务,且之前没有找到过            */
    if ( foundHdr == NULL )
    {
      prevHdr = listHdr;                                        /*  保存当前节点指针为上一次节点指针*/ 
    }
    listHdr = OSAL_MSG_NEXT( listHdr );                         /*  指向下一节点指针                */ 
  }
  /*  退出循环之后判断是没有消息,一条消息,还是多条消息        */
  // Is there more than one?
  /*  假如不为NULL,说明是多条消息,告诉任务还有消息是在等待的  */
  if ( listHdr != NULL )
  {
    // Yes, Signal the task that a message is waiting
    osal_set_event( task_id, SYS_EVENT_MSG );
  }
  else
  {
    // No more
    /*  只有一条消息或者没有消息  */
    osal_clear_event( task_id, SYS_EVENT_MSG );
  }
  
  // Did we find a message?
  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_hdr_t *listHdr;

 osal_msg_hdr_t *prevHdr = NULL;
 osal_msg_hdr_t *foundHdr = NULL;


 typedef void * osal_msg_q_t;

 osal_msg_q_t osal_qHead;

      listHdr = osal_qHead;            两个不同类型的指针赋值总感觉哪里不对呢?  

/**************************************************************************************************
 * @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(uint8 task_id, uint8 event)
{
  osal_msg_hdr_t *pHdr;
  halIntState_t intState;

  HAL_ENTER_CRITICAL_SECTION(intState);     // Hold off interrupts.
  /*  指向消息头  */
  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);
  }

  HAL_EXIT_CRITICAL_SECTION(intState);  // Release interrupts.

  return (osal_event_hdr_t *)pHdr;
}

/*********************************************************************
 * @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( osal_msg_q_t *q_ptr, void *msg_ptr )
{
  void *list;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);                             /*  关中断                      */

  OSAL_MSG_NEXT( msg_ptr ) = NULL;                                  /*  消息头next指向NULL          */
  /*  假如是第一条消息  */
  // If first message in queue
  if ( *q_ptr == NULL )
  {
    *q_ptr = msg_ptr;                                               /*  消息表头指向该消息          */
  }
  else
  {
    // Find end of queue
    for ( list = *q_ptr; OSAL_MSG_NEXT( list ) != NULL; list = OSAL_MSG_NEXT( list ) );

    // Add message to end of queue
    OSAL_MSG_NEXT( list ) = msg_ptr;                                /*  消息对尾节点next指向该消息  */
  }
  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);                              /*  开中断                      */
}

/*********************************************************************
 * @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( osal_msg_q_t *q_ptr )
{
  void *msg_ptr = NULL;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

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

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);

  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( osal_msg_q_t *q_ptr, void *msg_ptr )
{
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  // Push message to head of queue
  OSAL_MSG_NEXT( msg_ptr ) = *q_ptr;
  *q_ptr = msg_ptr;

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
}

/*********************************************************************
 * @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
 */
void osal_msg_extract( osal_msg_q_t *q_ptr, void *msg_ptr, void *prev_ptr )
{
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);                     /*  关中断                */

  /*  假如要找的消息为队首消息  */
  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 );
  }
  
  /*  释放的ID,为以后调用清除该消息准备条件  */
  OSAL_MSG_NEXT( msg_ptr ) = NULL;
  OSAL_MSG_ID( msg_ptr ) = TASK_NO_TASK;

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);                      /*  开中断                */
}

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复