BetaFlight模块设计之二十:CMS菜单模块分析

Posted lida2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BetaFlight模块设计之二十:CMS菜单模块分析相关的知识,希望对你有一定的参考价值。

BetaFlight模块设计之二十:CMS菜单模块分析

基于BetaFlight开源代码框架简介的框架设计,逐步分析内部模块功能设计。

CMS菜单模块

描述:将BetaFlight所有配置内容在不同的设备上进行CMS(Custom Menu System)菜单显示。

 ├──> 初始化
 │   ├──> [x]硬件初始化
 │   └──> [v]业务初始化cmsInit
 ├──> 任务
 │   ├──> [x]实时任务
 │   ├──> [x]事件任务
 │   └──> [v]时间任务[TASK_CMS] = DEFINE_TASK("CMS", NULL, NULL, cmsHandler, TASK_PERIOD_HZ(20), TASK_PRIORITY_LOW),
 ├──> 驱动
 │   ├──> [x]查询
 │   └──> [x]中断
 └──> 接口
     ├──> bool cmsDisplayPortRegister(displayPort_t *pDisplay);  //注册显示CMS菜单的设备,可以注册多个。
     ├──> void cmsMenuOpen(void); //打开菜单
     ├──> const void *cmsMenuChange(displayPort_t *pPort, const void *ptr); //进入子菜单
     ├──> const void *cmsMenuExit(displayPort_t *pPort, const void *ptr); //退出菜单
     ├──> void cmsAddMenuEntry(OSD_Entry *menuEntry, char *text, uint16_t flags, CMSEntryFuncPtr func, void *data);
     └──> void cmsSetExternKey(cms_key_e extKey);

注:多菜单显示设备支持,详见支持的设备类型。

typedef enum 
    DISPLAYPORT_DEVICE_TYPE_MAX7456 = 0,
    DISPLAYPORT_DEVICE_TYPE_OLED,
    DISPLAYPORT_DEVICE_TYPE_MSP,
    DISPLAYPORT_DEVICE_TYPE_FRSKYOSD,
    DISPLAYPORT_DEVICE_TYPE_CRSF,
    DISPLAYPORT_DEVICE_TYPE_HOTT,
    DISPLAYPORT_DEVICE_TYPE_SRXL,
 displayPortDeviceType_e;

CMS菜单按键控制

  • 打开菜单:IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH)
  • 进入菜单:IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) //菜单打开的情况下
  • 向上翻页: IS_HI(PITCH)
  • 向下翻页:IS_LO(PITCH)
  • 向左翻页:IS_LO(ROLL)
  • 向右翻页:IS_HI(ROLL)
  • 退出选项:IS_LO(YAW)
  • 保存菜单:IS_HI(YAW)

CMS菜单Elements

整个菜单从组成结构上由elements构成,分为两大类:CMS_Menu、OSD_Etnry。

CMS_Menu

typedef const void *(*CMSMenuFuncPtr)(displayPort_t *pDisp);
typedef const void *(*CMSMenuOnExitPtr)(displayPort_t *pDisp, const OSD_Entry *self);
typedef const void *(*CMSMenuOnDisplayUpdatePtr)(displayPort_t *pDisp, const OSD_Entry *selected);
typedef struct

#ifdef CMS_MENU_DEBUG
    // These two are debug aids for menu content creators.
    const char *GUARD_text;
    const OSD_MenuElement GUARD_type;
#endif
    const CMSMenuFuncPtr onEnter;
    const CMSMenuOnExitPtr onExit;
    const CMSMenuOnDisplayUpdatePtr onDisplayUpdate;
    const OSD_Entry *entries;
 CMS_Menu;

OSD_Etnry

typedef const void *(*CMSEntryFuncPtr)(displayPort_t *displayPort, const void *ptr);
typedef struct

    const char * text;
    // Logical OR of OSD_MenuElement and flags below
    uint16_t flags;
    CMSEntryFuncPtr func;
    void *data;
 __attribute__((packed)) OSD_Entry;

Element类型

各种类型对应的菜单操作详见cmsHandleKey函数。

typedef enum

    OME_Label,    //标记字符串
    OME_Back,     //返回前级菜单
    OME_OSD_Exit,
    OME_Submenu,  //子菜单类型
    OME_Funcall,  //执行函数
    OME_Bool,
    OME_INT8,     //OSD_INT8_t
    OME_UINT8,    //OSD_UINT8_t
    OME_UINT16,   //OSD_UINT16_t
    OME_INT16,    //OSD_INT16_t
    OME_UINT32,   //OSD_UINT32_t
    OME_INT32,    //OSD_INT32_t
    OME_String,   //OSD_String_t
    OME_FLOAT,    //OSD_FLOAT_t
#ifdef USE_OSD
    OME_VISIBLE,
#endif
    OME_TAB,      //OSD_TAB_t, 列表
    OME_END,

    // Debug aid
    OME_MENU,

    OME_MAX = OME_MENU
 OSD_MenuElement;

可调Element类型

typedef struct

    uint8_t *val;
    uint8_t min;
    uint8_t max;
    uint8_t step;
 OSD_UINT8_t;

typedef struct

    int8_t *val;
    int8_t min;
    int8_t max;
    int8_t step;
 OSD_INT8_t;

typedef struct

    int16_t *val;
    int16_t min;
    int16_t max;
    int16_t step;
 OSD_INT16_t;

typedef struct

    uint16_t *val;
    uint16_t min;
    uint16_t max;
    uint16_t step;
 OSD_UINT16_t;

typedef struct

    int32_t *val;
    int32_t min;
    int32_t max;
    int32_t step;
 OSD_INT32_t;

typedef struct

    uint32_t *val;
    uint32_t min;
    uint32_t max;
    uint32_t step;
 OSD_UINT32_t;

typedef struct

    uint8_t *val;
    uint8_t min;
    uint8_t max;
    uint8_t step;
    uint16_t multipler;
 OSD_FLOAT_t;

typedef struct

    uint8_t *val;
    uint8_t max;
    const char * const *names;
 OSD_TAB_t;

CMS菜单结构

第一层菜单(Top Menu)

CMS_Menu cmsx_menuMain = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "MENUMAIN",
    .GUARD_type = OME_MENU,
#endif
    .onEnter = mainMenuOnEnter,
    .onExit = NULL,
    .onDisplayUpdate = NULL,
    .entries = menuMainEntries,
;
static const OSD_Entry menuMainEntries[] =

    "-- MAIN --",  OME_Label, NULL, NULL,

    "PROFILE",     OME_Submenu,  cmsMenuChange, &cmsx_menuImu,
    "FEATURES",    OME_Submenu,  cmsMenuChange, &cmsx_menuFeatures,
#ifdef USE_OSD
    "OSD",         OME_Submenu,  cmsMenuChange, &cmsx_menuOsd,
#endif
    "FC&FIRMWARE", OME_Submenu,  cmsMenuChange, &cmsx_menuFirmware,
    "MISC",        OME_Submenu,  cmsMenuChange, &cmsx_menuMisc,
    "SAVE/EXIT",   OME_Funcall,  cmsx_SaveExitMenu, NULL,
    NULL, OME_END, NULL, NULL,
;

第二层菜单(SubMenu)

IMU菜单

CMS_Menu cmsx_menuImu = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "XIMU",
    .GUARD_type = OME_MENU,
#endif
    .onEnter = cmsx_menuImu_onEnter,
    .onExit = cmsx_menuImu_onExit,
    .onDisplayUpdate = NULL,
    .entries = cmsx_menuImuEntries,
;
static const OSD_Entry cmsx_menuImuEntries[] =

     "-- PROFILE --", OME_Label, NULL, NULL,

    "PID PROF",  OME_UINT8,   cmsx_profileIndexOnChange,     &(OSD_UINT8_t) &tmpPidProfileIndex, 1, PID_PROFILE_COUNT, 1,
    "PID",       OME_Submenu, cmsMenuChange,                 &cmsx_menuPid,
#ifdef USE_SIMPLIFIED_TUNING
    "SIMPLIFIED TUNING",   OME_Submenu, cmsMenuChange,                 &cmsx_menuSimplifiedTuning,
#endif
    "MISC PP",   OME_Submenu, cmsMenuChange,                 &cmsx_menuProfileOther,
    "FILT PP",   OME_Submenu, cmsMenuChange,                 &cmsx_menuFilterPerProfile,

    "RATE PROF", OME_UINT8,   cmsx_rateProfileIndexOnChange, &(OSD_UINT8_t) &tmpRateProfileIndex, 1, CONTROL_RATE_PROFILE_COUNT, 1,
    "RATE",      OME_Submenu, cmsMenuChange,                 &cmsx_menuRateProfile,

    "FILT GLB",  OME_Submenu, cmsMenuChange,                 &cmsx_menuFilterGlobal,
#if  (defined(USE_DYN_NOTCH_FILTER) || defined(USE_DYN_LPF)) && defined(USE_EXTENDED_CMS_MENUS)
    "DYN FILT",  OME_Submenu, cmsMenuChange,                 &cmsx_menuDynFilt,
#endif

#ifdef USE_EXTENDED_CMS_MENUS
    "COPY PROF", OME_Submenu, cmsMenuChange,                 &cmsx_menuCopyProfile,
#endif /* USE_EXTENDED_CMS_MENUS */

    "BACK", OME_Back, NULL, NULL,
    NULL, OME_END, NULL, NULL
;

FEATURES菜单

static CMS_Menu cmsx_menuFeatures = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "MENUFEATURES",
    .GUARD_type = OME_MENU,
#endif
    .onEnter = NULL,
    .onExit = NULL,
    .onDisplayUpdate = NULL,
    .entries = menuFeaturesEntries,
;
static const OSD_Entry menuFeaturesEntries[] =

    "--- FEATURES ---", OME_Label, NULL, NULL,

#if defined(USE_BLACKBOX)
    "BLACKBOX", OME_Submenu, cmsMenuChange, &cmsx_menuBlackbox,
#endif
#if defined(USE_VTX_CONTROL)
#if defined(USE_VTX_RTC6705) || defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP)
    "VTX", OME_Funcall, cmsSelectVtx, NULL,
#endif
#endif // VTX_CONTROL
#ifdef USE_LED_STRIP
    "LED STRIP", OME_Submenu, cmsMenuChange, &cmsx_menuLedstrip,
#endif // LED_STRIP
    "POWER", OME_Submenu, cmsMenuChange, &cmsx_menuPower,
#ifdef USE_CMS_FAILSAFE_MENU
    "FAILSAFE", OME_Submenu, cmsMenuChange, &cmsx_menuFailsafe,
#endif
#ifdef USE_PERSISTENT_STATS
    "PERSISTENT STATS", OME_Submenu, cmsMenuChange, &cmsx_menuPersistentStats,
#endif
    "BACK", OME_Back, NULL, NULL,
    NULL, OME_END, NULL, NULL
;

CMS菜单

CMS_Menu cmsx_menuOsd = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "MENUOSD",
    .GUARD_type = OME_MENU,
#endif
    .onEnter = cmsx_menuOsdOnEnter,
    .onExit = cmsx_menuOsdOnExit,
    .onDisplayUpdate = NULL,
    .entries = cmsx_menuOsdEntries
;
const OSD_Entry cmsx_menuOsdEntries[] =

    "---OSD---",   OME_Label,   NULL,          NULL,
#ifdef USE_OSD_PROFILES
    "OSD PROFILE", OME_UINT8, NULL, &(OSD_UINT8_t)&osdConfig_osdProfileIndex, 1, 3, 1,
#endif
#ifdef USE_EXTENDED_CMS_MENUS
    "ACTIVE ELEM", OME_Submenu, cmsMenuChange, &menuOsdActiveElems,
    "TIMERS",      OME_Submenu, cmsMenuChange, &menuTimers,
    "ALARMS",      OME_Submenu, cmsMenuChange, &menuAlarms,
#endif
#ifdef USE_MAX7456
    "INVERT",    OME_Bool,  cmsx_max7456Update, &displayPortProfileMax7456_invert,
    "BRT BLACK", OME_UINT8, cmsx_max7456Update, &(OSD_UINT8_t)&displayPortProfileMax7456_blackBrightness, 0, 3, 1,
    "BRT WHITE", OME_UINT8, cmsx_max7456Update, &(OSD_UINT8_t)&displayPortProfileMax7456_whiteBrightness, 0, 3, 1,
#endif
    "BACKGROUND",OME_TAB,   cmsx_osdBackgroundUpdate, &(OSD_TAB_t)&osdMenuBackgroundType, DISPLAY_BACKGROUND_COUNT - 1, lookupTableCMSMenuBackgroundType,
    "BACK", OME_Back, NULL, NULL,
    NULL,   OME_END,  NULL, NULL
;

FIRMWARE菜单

CMS_Menu cmsx_menuFirmware = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "MENUFIRMWARE",
    .GUARD_type = OME_MENU,
#endif
#if defined(USE_BOARD_INFO)
    .onEnter = cmsx_FirmwareInit,
#else
    .onEnter = NULL,
#endif
    .onExit = NULL,
    .onDisplayUpdate = NULL,
    .entries = menuFirmwareEntries
;
static const OSD_Entry menuFirmwareEntries[] = 
     "--- INFO ---", OME_Label, NULL, NULL ,
     "FWID", OME_String, NULL, FC_FIRMWARE_IDENTIFIER ,
     "FWVER", OME_String, NULL, FC_VERSION_STRING ,
     "GITREV", OME_String, NULL, __REVISION__ ,
     "TARGET", OME_String, NULL, __TARGET__ ,
#if defined(USE_BOARD_INFO)
     "MFR", OME_String, NULL, manufacturerId ,
     "BOARD", OME_String, NULL, boardName ,
#endif
     "--- SETUP ---", OME_Label, NULL, NULL ,
     "CALIBRATE",     OME_Submenu, cmsMenuChange, &cmsx_menuCalibration,
     "BACK", OME_Back, NULL, NULL ,
     NULL, OME_END, NULL, NULL
;

MISC菜单

CMS_Menu cmsx_menuMisc = 
#ifdef CMS_MENU_DEBUG
    .GUARD_text = "XMISC",
    .GUARD_type = OME_MENU,
#endif
    .onEnter = cmsx_menuMiscOnEnter,
    .onExit = cmsx_menuMiscOnExit,
    .onDisplayUpdate = NULL,
    .entries = menuMiscEntries
;
static const OSD_Entry menuMiscEntries[]=

     "-- MISC --", OME_Label, NULL, NULL ,

     "MIN THR",       OME_UINT16 | REBOOT_REQUIRED,  NULL,          &(OSD_UINT16_t) &motorConfig_minthrottle,            1000, 2000, 1  ,
     "DIGITAL IDLE",  OME_UINT8 | REBOOT_REQUIRED,   NULL,          &(OSD_UINT8_t)  &motorConfig_digitalIdleOffsetValue,    0,  200, 1  ,
     "FPV CAM ANGLE", OME_UINT8,   NULL,          &(OSD_UINT8_t)  &rxConfig_fpvCamAngleDegrees,           0,   90, 1  ,
     "RC PREV",       OME_Submenu, cmsMenuChange, &cmsx_menuRcPreview,

     "BACK", OME_Back, NULL, NULL,
     NULL, OME_END, NULL, NULL
;

注:只要是OME_Submenu类型的OSD_Entry就一直能通过cmsMenuChange进入下级菜单。

CMS菜单代码

所有菜单相关代码在src/main/cms/路径下。

src/main/cms/
  ├── cms_types.h            //CMS菜单相关类型定义
  ├── cms.c                  //CMS菜单控制操作
  ├── cms.h                  //CMS菜单模块对外接口定义
  ├── cms_menu_blackbox.c
  ├── cms_menu_blackbox.h     
  ├── cms_menu_failsafe.c
  ├── cms_menu_failsafe.h
  ├── cms_menu_firmware.c
  ├── cms_menu_firmware.h
  ├── cms_menu_gps_rescue.c
  ├── cms_menu_gps_rescue.h
  ├── cms_menu_imu.c
  ├── cms_menu_imu.h
  ├── cms_menu_ledstrip.c
  ├── cms_menu_ledstrip.h
  ├── cms_menu_main.c
  ├── cms_menu_main.h
  ├── cms_menu_misc.c
  ├── cms_menu_misc.h
  ├── cms_menu_osd.c
  ├── cms_menu_osd.h
  ├── cms_menu_persistent_stats.c
  ├── cms_menu_persistent_stats.h
  ├── cms_menu_power.c
  ├── cms_menu_power.h
  ├── cms_menu_saveexit.c
  ├── cms_menu_saveexit.h
  ├── cms_menu_vtx_common.c
  ├── cms_menu_vtx_common.h
  ├── cms_menu_vtx_rtc6705.c
  ├── cms_menu_vtx_rtc6705.h
  ├── cms_menu_vtx_smartaudio.c
  ├── cms_menu_vtx_smartaudio.h
  ├── cms_menu_vtx_tramp.c
  └── cms_menu_vtx_tramp.h
  
  
  0 directories, 35 files

主要函数分析

cmsHandler

排除没有CMS菜单显示设备的情况。

cmsHandler
 

以上是关于BetaFlight模块设计之二十:CMS菜单模块分析的主要内容,如果未能解决你的问题,请参考以下文章

BetaFlight模块设计之二十六:接收机任务分析

BetaFlight模块设计之二十九:滤波模块分析

BetaFlight模块设计之二十八:MainPidLoop任务分析

BetaFlight模块设计之二十二:地面测距任务分析

BetaFlight模块设计之二十一:dashboard任务分析

BetaFlight模块设计之二十五:dispatch任务分析