当前位置:   article > 正文

RTX RTOS操作实例分析之---邮箱(mailbox)

RTX RTOS操作实例分析之---邮箱(mailbox)

0 Preface/Foreword

1 邮箱(mailbox)

1.1 mailbox ID定义

 static osMailQId app_mailbox = NULL;

 1.2 定义mailbox结构体变量

#define osMailQDef(name, queue_sz, type) \
static void *os_mail_p_##name[2]; \
const char mail_##name[] = #name; \
const osMailQDef_t os_mailQ_def_##name = \
{ (queue_sz), sizeof(type), (&os_mail_p_##name), \
  { NULL, 0U, NULL, 0U, NULL, 0U }, \
  { mail_##name, 0U, NULL, 0U, NULL, 0U } }

osMailQDef,三个参数

  • name,名字
  • queue_sz,队列中,总共元素个数
  • type,元素大小

实例分析

 osMailQDef (app_mailbox, APP_MAILBOX_MAX, APP_MESSAGE_BLOCK);

#define APP_MAILBOX_MAX (20) 

 APP_MAILBOX_MAX: 20

APP_MESSAGE_BLOCK,为一个结构体类型数据,具体见section 1.3。 

1.3 APP_MESSAGE_BLOCK

 typedef struct {
    uint32_t src_thread;
    uint32_t dest_thread;
    uint32_t system_time;
    uint32_t mod_id;
    enum APP_MOD_LEVEL_E mod_level;
    APP_MESSAGE_BODY msg_body;
} APP_MESSAGE_BLOCK;

 1.3.1 APP_MESSAGE_BODY

typedef struct {
    uint32_t message_id;
    uint32_t message_ptr;
    uint32_t message_Param0;
    uint32_t message_Param1;
    uint32_t message_Param2;
    float    message_Param3;
#if defined(USE_BASIC_THREADS)
    void* p;
#endif
} APP_MESSAGE_BODY;

1.3.2 APP_MOD_LEVEL_E

enum APP_MOD_LEVEL_E {
    APP_MOD_LEVEL_0 = 0,
    APP_MOD_LEVEL_1,
    APP_MOD_LEVEL_2,
}; 

1.3.3 APP_MODULE_ID_T

#ifndef CHIP_SUBSYS_SENS
enum APP_MODUAL_ID_T {
    APP_MODUAL_KEY = 0,
    APP_MODUAL_AUDIO,
    APP_MODUAL_BATTERY,
    APP_MODUAL_BT,
    APP_MODUAL_FM,
    APP_MODUAL_SD,
    APP_MODUAL_LINEIN,
    APP_MODUAL_USBHOST,
    APP_MODUAL_USBDEVICE,
    APP_MODUAL_WATCHDOG,
    APP_MODUAL_ANC,
    APP_MODUAL_VOICE_ASSIST,
    APP_MODUAL_SMART_MIC,
    APP_MODUAL_CAPSENSOR,
#ifdef __PC_CMD_UART__
    APP_MODUAL_CMD,
#endif
#ifdef TILE_DATAPATH
    APP_MODUAL_TILE,
#endif
    APP_MODUAL_MIC,
#ifdef VOICE_DETECTOR_EN
    APP_MODUAL_VOICE_DETECTOR,
#endif
#ifdef AUDIO_HEARING_COMPSATN
    APP_MODUAL_HEAR_COMP,
#endif
    APP_MODUAL_OHTER,
#if defined(USE_BASIC_THREADS)
    APP_MODUAL_AUDIO_MANAGE,
    APP_MODUAL_MEDIA,
    APP_MODUAL_BTSYNC,
    APP_MODUAL_ANC_FADE,
    APP_MODUAL_UX,
    APP_MODUAL_TWSCTRL,
#else
    APP_MODUAL_CUSTOM0,
    APP_MODUAL_CUSTOM1,
    APP_MODUAL_CUSTOM2,
    APP_MODUAL_CUSTOM3,
    APP_MODUAL_CUSTOM4,
    APP_MODUAL_CUSTOM5,
#endif
#if defined (_OSM_HOST_FUNC_)
    APP_MODUAL_P27WLC_II,
#endif
    APP_MODUAL_NUM
};

#else /* defined(CHIP_SUBSYS_SENS) */
enum APP_MODUAL_ID_T {
    APP_MODUAL_KEY = 0,
    APP_MODUAL_AUDIO,
#ifdef VOICE_DETECTOR_EN
    APP_MODUAL_VOICE_DETECTOR,
#endif
    APP_MODUAL_OHTER,

    APP_MODUAL_NUM
};
#endif /* CHIP_SUBSYS_SENS */

CHIP_SUBSYS_SENS :该宏有没有定义呢?通过makefile文件追溯可知,该宏没有定义,详情如下:

 1.4 获取邮箱结构体变量

 osMailQ(app_mailbox)

app_mailbox,该名字和定义时的名字需要相同。

1.5 创建mailbox对象(object) 

 app_mailbox = osMailCreate(osMailQ(app_mailbox), NULL);

有两个参数:

  • 定义的结构体变量地址
  • 线程ID,没有实际作用 

 1.5.1 osMailCreate implementation

osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id) {
  os_mail_queue_t *ptr;
  (void)thread_id;

  if (queue_def == NULL) {
    return (osMailQId)NULL;
  }

  ptr = queue_def->mail;
  if (ptr == NULL) {
    return (osMailQId)NULL;
  }

  ptr->mp_id = osMemoryPoolNew  (queue_def->queue_sz, queue_def->item_sz, &queue_def->mp_attr);
  ptr->mq_id = osMessageQueueNew(queue_def->queue_sz, sizeof(void *), &queue_def->mq_attr);
  if ((ptr->mp_id == (osMemoryPoolId_t)NULL) || (ptr->mq_id == (osMessageQueueId_t)NULL)) {
    if (ptr->mp_id != (osMemoryPoolId_t)NULL) {
      osMemoryPoolDelete(ptr->mp_id);
    }
    if (ptr->mq_id != (osMessageQueueId_t)NULL) {
      osMessageQueueDelete(ptr->mq_id);
    }
    return (osMailQId)NULL;
  }

  return (osMailQId)ptr;
}

主要功能

  • 根据mailbox的大小,动态分配内存池
  • 根据mailbox大小,动态分配消息队列 
  • 返回一个对象指针,该指针原始值为数组。

1.5.2  os_mail_queue_t

 typedef struct os_mail_queue_s {
  osMemoryPoolId_t   mp_id;
  osMessageQueueId_t mq_id;
} os_mail_queue_t;

 作用:保护两个成员,分别用于存放memory pool ID和message queue ID。

1.6 osMailGet 

osEvent osMailGet (osMailQId queue_id, uint32_t millisec) {
  os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
  osStatus_t       status;
  osEvent          event;
  void            *mail;

  if (ptr == NULL) {
    event.status = osErrorParameter;
    return event;
  }

  status = osMessageQueueGet(ptr->mq_id, &mail, NULL, millisec);
  switch (status) {
    case osOK:
      event.status = osEventMail;
      event.value.p = mail;
      break;
    case osErrorResource:
      event.status = osOK;
      break;
    case osErrorTimeout:
      event.status = osEventTimeout;
      break;
    default:
      event.status = status;
      break;
  }
  return event;
}

主要功能:

  • 通过osMessageQueueGet获取消息 

1.6.1 osMessageQueueGet

从消息队列中获取消息,或者如果消息队列为空则等待timetout 

/// Get a Message from a Queue or timeout if Queue is empty.
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
  osStatus_t status;

  EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  if (IsIrqMode() || IsIrqMasked()) {
    status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  } else {
    status =  __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
  }
  return status;
}

NOTE:

  •  __svcMessageQueueGet在哪里实现?库?内敛函数?宏函数?

验证发现:所有的都是调用__svcMessageQueueGet而不是isrRtxMessageQueueGet。(如下截图所示)

 

1.7 osMailAlloc 

void *osMailAlloc (osMailQId queue_id, uint32_t millisec) {
  os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;

  if (ptr == NULL) {
    return NULL;
  }
  return osMemoryPoolAlloc(ptr->mp_id, millisec);
}

/// Allocate a memory block from a Memory Pool.
void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
  void *memory;

  EvrRtxMemoryPoolAlloc(mp_id, timeout);
  if (IsIrqMode() || IsIrqMasked()) {
    memory = isrRtxMemoryPoolAlloc(mp_id, timeout);
  } else {
    memory =  __svcMemoryPoolAlloc(mp_id, timeout);
  }
  return memory;
}

NOTE:

  • 从内存池中分配一个内存块

1.8 osMailPut 

osStatus osMailPut (osMailQId queue_id, const void *mail) {
  os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;

  if (ptr == NULL) {
    return osErrorParameter;
  }
  if (mail == NULL) {
    return osErrorValue;
  }
  return osMessageQueuePut(ptr->mq_id, &mail, 0U, 0U);
}

NOTE:osMessageQueuePut参数中,为什么需要取mail的地址? 如果不取地址,会有什么结果?

验证发现:机器死机,插适配器充电无法恢复,并且无法继续固件升级。(设备变砖) 

/// Put a Message into a Queue or timeout if Queue is full.
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
  osStatus_t status;

  EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  if (IsIrqMode() || IsIrqMasked()) {
    status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  } else {
    status =  __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
  }
  return status;
}

1.9 osMailFree

osStatus osMailFree (osMailQId queue_id, void *mail) {
  os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;

  if (ptr == NULL) {
    return osErrorParameter;
  }
  if (mail == NULL) {
    return osErrorValue;
  }
  return osMemoryPoolFree(ptr->mp_id, mail);
}

/// Return an allocated memory block back to a Memory Pool.
osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
  osStatus_t status;

  EvrRtxMemoryPoolFree(mp_id, block);
  if (IsIrqMode() || IsIrqMasked()) {
    status = isrRtxMemoryPoolFree(mp_id, block);
  } else {
    status =  __svcMemoryPoolFree(mp_id, block);
  }
  return status;
}

2 生产者(producer)

2.1 app_mailbox_put

int app_mailbox_put(APP_MESSAGE_BLOCK* msg_src)
{
    osStatus status;
//    osMutexWait(app_mutex_id, osWaitForever);

    APP_MESSAGE_BLOCK *msg_p = NULL;

    msg_p = (APP_MESSAGE_BLOCK*)osMailAlloc(app_mailbox, 0);

    if (!msg_p){
        osEvent evt;
        TRACE_IMM(0,"osMailAlloc error dump");
        for (uint8_t i=0; i<APP_MAILBOX_MAX; i++){
            evt = osMailGet(app_mailbox, 0);
            if (evt.status == osEventMail) {
                TRACE_IMM(9,"cnt:%d mod:%d level:%d src:%08x tim:%d id:%8x ptr:%08x para:%08x/%08x/%08x/%08x",
                            i,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->mod_id,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->mod_level,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->src_thread,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->system_time,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_id,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_ptr,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param0,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param1,
                            ((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param2,
                            (uint32_t)((APP_MESSAGE_BLOCK *)(evt.value.p))->msg_body.message_Param3);
            }else{
                TRACE_IMM(2,"cnt:%d %d", i, evt.status);
                break;
            }
        }
        TRACE_IMM(0,"osMailAlloc error dump end");
    }

    ASSERT(msg_p, "osMailAlloc error");
    msg_p->src_thread = (uint32_t)osThreadGetId();
    msg_p->dest_thread = (uint32_t)NULL;
    msg_p->system_time = hal_sys_timer_get();
    msg_p->mod_id = msg_src->mod_id;
    msg_p->mod_level = msg_src->mod_level;
    msg_p->msg_body.message_id = msg_src->msg_body.message_id;
    msg_p->msg_body.message_ptr = msg_src->msg_body.message_ptr;
    msg_p->msg_body.message_Param0 = msg_src->msg_body.message_Param0;
    msg_p->msg_body.message_Param1 = msg_src->msg_body.message_Param1;
    msg_p->msg_body.message_Param2 = msg_src->msg_body.message_Param2;
    msg_p->msg_body.message_Param3 = msg_src->msg_body.message_Param3;
    msg_p->msg_body.p = msg_src->msg_body.p;

    status = osMailPut(app_mailbox, msg_p);
//    osMutexRelease(app_mutex_id);
    return (int)status;
}

3 消费者(consumer)

3.1 app_mailbox_get 

app_mailbox_get由app_thread调用。 

3.2 app_mailbox_process

 int app_mailbox_process(APP_MESSAGE_BLOCK* msg_p)
{
    if (msg_p->mod_id < APP_MODUAL_NUM){
        if (mod_handler[msg_p->mod_id]){
            int ret = 0 ;
            if(APP_MODUAL_AUDIO_MANAGE == msg_p->mod_id){
                int Priority = osThreadGetPriority(app_thread_tid);
                osThreadSetPriority(app_thread_tid, osPriorityRealtime);
                ret = mod_handler[msg_p->mod_id](&(msg_p->msg_body));
                osThreadSetPriority(app_thread_tid, Priority);
            }else{
                ret = mod_handler[msg_p->mod_id](&(msg_p->msg_body));
            }
            if (ret)
                TRACE(2,"%s, mod_handler[%d] ret=%d", __func__, msg_p->mod_id, ret);
        }
    }
    return 0;
}

NOTE:最终消息处理是在各自模块中实现。(回调函数) 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/394089
推荐阅读
相关标签
  

闽ICP备14008679号