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:最终消息处理是在各自模块中实现。(回调函数) 

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

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

相关文章

iOS 17.5系统或可识别并禁用未知跟踪器,苹果Find My技术应用越来越合理

苹果公司去年与谷歌合作&#xff0c;宣布将制定新的行业标准来解决人们日益关注的跟踪器隐私问题。苹果计划在即将发布的 iOS 17.5 系统中加入这项提升用户隐私保护的新功能。 科技网站 9to5Mac 在苹果发布的 iOS 17.5 开发者测试版内部代码中发现了这项反跟踪功能的蛛丝马迹…

15-1-Flex布局

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 Flex布局1 Flex容器和Flex项目2 Flex 容器属性2.1 主轴的方向2.2 主轴对齐方式…

Linux(CentOS7)安装 Docker 以及 Docker 基本使用教程

目录 安装 基础依赖 安装 docker 开机自启 启动 docker 配置国内镜像源 使用教程 帮助命令 镜像命令 容器命令 容器终端 构建镜像 安装 基础依赖 如果直接安装 docker 时报错&#xff0c;提示缺少依赖&#xff0c;则根据提示将前置依赖安装即可&#xff0c;这里直…

工业4g路由器联网后迅速掉线是什么原因?

工业4G路由器连接上网后迅速掉线可能是由多种因素造成的。以下是一些建议的检查和解决步骤&#xff1a; 1、信号问题&#xff1a; 信号强度&#xff1a;检查工业路由器信号强度指示灯&#xff0c;如果信号弱&#xff0c;尝试移动路由器位置或添加外部天线来增强信号。 网络拥…

FIN和RST的区别,几种TCP连接出现RST的情况

一、RST跟FIN的区别&#xff1a; 正常关闭连接的时候发的包是FIN&#xff0c;但是如果是异常关闭连接&#xff0c;则发送RST包 两者的区别在于&#xff1a; 1.RST不必等缓冲区的包都发出去&#xff0c;直接就丢弃缓存区的包发送RST包。而FIN需要先处理完缓存区的包才能发送F…

C++ | Leetcode C++题解之第15题三数之和

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> threeSum(vector<int>& nums) {int n nums.size();sort(nums.begin(), nums.end());vector<vector<int>> ans;// 枚举 afor (int first 0; first < n…

二. CUDA编程入门-双线性插值计算

目录 前言0. 简述1. 执行一下我们的第十个CUDA程序2. Bilinear interpolation3. 代码分析总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 Note&#xff1a;关于 CUDA 加速双线程插值的内容博主…

elementPlus el-table动态列扩展及二维表格

1、循环列数据源&#xff0c;动态生成列 <template><div><el-table ref"table" :data"pageData.tableData" stripe style"width: 100%"><el-table-column v-for"column in pageData.columns" :key"column.p…

LDR6328助力Type-C普及,便捷充电,绿色生活更精彩

随着科技的进步和全球统一接口的需求&#xff0c;Type-C接口正日益受到青睐。越来越多的设备正选择采纳这一先进的接口设计&#xff0c;它的普及无疑在改善着我们的日常生活。 在过往&#xff0c;许多小功率设备如小风扇、蓝牙音箱、桌面台灯以及家用加湿器等&#xff0c;都普遍…

单片机IGBT驱动电路一例

概述&#xff1a; 驱动的作用有三个&#xff1a; 1.是作为放大器获得所需要的驱动电压。 2.是提高输出电流能力。 3.是进行功率回路和控制回路的隔离 信号从MCU到IGBT驱动芯片 首先驱动电流需要放大 MCU的输出电流是mA级别&#xff0c;而IGBT需要的驱动电流可能达到几安培…

npm版本切换工具nvm

有了nvm&#xff0c;可以在一台机器上同时安装多个版本的nodejs&#xff0c;然后指定使用某个版本。 前端开发的时候&#xff0c;安装依赖一直是个令我头痛的问题。总是报错&#xff0c;或者不是少了这样就是少了那样&#xff0c;鸡飞狗走。以往&#xff0c;一般要装个enpm&am…

【氮化镓】在轨实验研究辐射对GaN器件的影响

【Pioneering evaluation of GaN transistors in geostationary satellites】 摘要&#xff1a; 这篇论文介绍了一项为期6年的空间实验结果&#xff0c;该实验研究了在地球静止轨道上辐射对氮化镓&#xff08;GaN&#xff09;电子元件的影响。实验使用了四个GaN晶体管&#xf…