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模块设计之二十八:MainPidLoop任务分析