mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-24 00:35:34 +03:00
Merge pull request #2955 from iNavFlight/agh_osd_layouts
Add support for multiple OSD layouts
This commit is contained in:
commit
e3dafbf516
18 changed files with 719 additions and 422 deletions
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "cms/cms.h"
|
||||
#include "cms/cms_menu_builtin.h"
|
||||
#include "cms/cms_menu_osd.h"
|
||||
#include "cms/cms_types.h"
|
||||
|
||||
#include "common/maths.h"
|
||||
|
@ -94,6 +95,7 @@ static displayPort_t *pCurrentDisplay;
|
|||
static displayPort_t *cmsDisplayPorts[CMS_MAX_DEVICE];
|
||||
static int cmsDeviceCount;
|
||||
static int cmsCurrentDevice = -1;
|
||||
static timeMs_t cmsYieldUntil = 0;
|
||||
|
||||
bool cmsDisplayPortRegister(displayPort_t *pDisplay)
|
||||
{
|
||||
|
@ -349,21 +351,6 @@ static int cmsDrawMenuEntry(displayPort_t *pDisplay, const OSD_Entry *p, uint8_t
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_OSD
|
||||
case OME_VISIBLE:
|
||||
if (IS_PRINTVALUE(p, screenRow) && p->data) {
|
||||
uint16_t val = osdConfig()->item_pos[(int)p->data];
|
||||
|
||||
if (VISIBLE(val)) {
|
||||
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "YES");
|
||||
} else {
|
||||
cnt = displayWrite(pDisplay, RIGHT_MENU_COLUMN(pDisplay), row, "NO ");
|
||||
}
|
||||
CLR_PRINTVALUE(p, screenRow);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case OME_UINT8:
|
||||
if (IS_PRINTVALUE(p, screenRow) && p->data) {
|
||||
const uint8_t *val;
|
||||
|
@ -636,10 +623,8 @@ static void cmsMenuCountPage(displayPort_t *pDisplay)
|
|||
|
||||
STATIC_UNIT_TESTED long cmsMenuBack(displayPort_t *pDisplay); // Forward; will be resolved after merging
|
||||
|
||||
long cmsMenuChange(displayPort_t *pDisplay, const void *ptr)
|
||||
long cmsMenuChange(displayPort_t *pDisplay, const CMS_Menu *pMenu, const OSD_Entry *from)
|
||||
{
|
||||
CMS_Menu *pMenu = (CMS_Menu *)ptr;
|
||||
|
||||
if (!pMenu) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -664,7 +649,7 @@ long cmsMenuChange(displayPort_t *pDisplay, const void *ptr)
|
|||
currentCtx.menu = pMenu;
|
||||
currentCtx.cursorRow = 0;
|
||||
|
||||
if (pMenu->onEnter && (pMenu->onEnter() == MENU_CHAIN_BACK)) {
|
||||
if (pMenu->onEnter && (pMenu->onEnter(from) == MENU_CHAIN_BACK)) {
|
||||
return cmsMenuBack(pDisplay);
|
||||
}
|
||||
|
||||
|
@ -731,7 +716,7 @@ STATIC_UNIT_TESTED void cmsMenuOpen(void)
|
|||
}
|
||||
}
|
||||
displayGrab(pCurrentDisplay); // grab the display for use by the CMS
|
||||
cmsMenuChange(pCurrentDisplay, currentCtx.menu);
|
||||
cmsMenuChange(pCurrentDisplay, currentCtx.menu, NULL);
|
||||
}
|
||||
|
||||
static void cmsTraverseGlobalExit(const CMS_Menu *pMenu)
|
||||
|
@ -743,7 +728,7 @@ static void cmsTraverseGlobalExit(const CMS_Menu *pMenu)
|
|||
}
|
||||
|
||||
if (pMenu->onGlobalExit) {
|
||||
pMenu->onGlobalExit();
|
||||
pMenu->onGlobalExit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -789,6 +774,12 @@ long cmsMenuExit(displayPort_t *pDisplay, const void *ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void cmsYieldDisplay(displayPort_t *pPort, timeMs_t duration)
|
||||
{
|
||||
cmsYieldUntil = millis() + duration;
|
||||
displayRelease(pPort);
|
||||
}
|
||||
|
||||
// Stick/key detection and key codes
|
||||
|
||||
#define IS_HI(X) (rcData[X] > 1750)
|
||||
|
@ -855,7 +846,7 @@ STATIC_UNIT_TESTED uint16_t cmsHandleKey(displayPort_t *pDisplay, uint8_t key)
|
|||
switch (p->type) {
|
||||
case OME_Submenu:
|
||||
if (key == KEY_RIGHT) {
|
||||
cmsMenuChange(pDisplay, p->data);
|
||||
cmsMenuChange(pDisplay, p->data, p);
|
||||
res = BUTTON_PAUSE;
|
||||
}
|
||||
break;
|
||||
|
@ -889,6 +880,9 @@ STATIC_UNIT_TESTED uint16_t cmsHandleKey(displayPort_t *pDisplay, uint8_t key)
|
|||
else
|
||||
*val = 0;
|
||||
SET_PRINTVALUE(p, currentCtx.cursorRow);
|
||||
if (p->func) {
|
||||
p->func(pDisplay, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -901,20 +895,6 @@ STATIC_UNIT_TESTED uint16_t cmsHandleKey(displayPort_t *pDisplay, uint8_t key)
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_OSD
|
||||
case OME_VISIBLE:
|
||||
if (p->data) {
|
||||
uint16_t *val = &osdConfigMutable()->item_pos[(int)p->data];
|
||||
|
||||
if (key == KEY_RIGHT)
|
||||
*val |= VISIBLE_FLAG;
|
||||
else
|
||||
*val %= ~VISIBLE_FLAG;
|
||||
SET_PRINTVALUE(p, currentCtx.cursorRow);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case OME_UINT8:
|
||||
case OME_FLOAT:
|
||||
if (IS_READONLY(p)) {
|
||||
|
@ -1107,6 +1087,97 @@ uint16_t cmsHandleKeyWithRepeat(displayPort_t *pDisplay, uint8_t key, int repeat
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t cmsScanKeys(timeMs_t currentTimeMs, timeMs_t lastCalledMs, int16_t rcDelayMs)
|
||||
{
|
||||
static int holdCount = 1;
|
||||
static int repeatCount = 1;
|
||||
static int repeatBase = 0;
|
||||
|
||||
//
|
||||
// Scan 'key' first
|
||||
//
|
||||
|
||||
uint8_t key = KEY_NONE;
|
||||
|
||||
if (IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) && !ARMING_FLAG(ARMED)) {
|
||||
key = KEY_MENU;
|
||||
}
|
||||
else if (IS_HI(PITCH)) {
|
||||
key = KEY_UP;
|
||||
}
|
||||
else if (IS_LO(PITCH)) {
|
||||
key = KEY_DOWN;
|
||||
}
|
||||
else if (IS_LO(ROLL)) {
|
||||
key = KEY_LEFT;
|
||||
}
|
||||
else if (IS_HI(ROLL)) {
|
||||
key = KEY_RIGHT;
|
||||
}
|
||||
else if (IS_HI(YAW) || IS_LO(YAW))
|
||||
{
|
||||
key = KEY_ESC;
|
||||
}
|
||||
|
||||
if (key == KEY_NONE) {
|
||||
// No 'key' pressed, reset repeat control
|
||||
holdCount = 1;
|
||||
repeatCount = 1;
|
||||
repeatBase = 0;
|
||||
} else {
|
||||
// The 'key' is being pressed; keep counting
|
||||
++holdCount;
|
||||
}
|
||||
|
||||
if (rcDelayMs > 0) {
|
||||
rcDelayMs -= (currentTimeMs - lastCalledMs);
|
||||
} else if (key) {
|
||||
rcDelayMs = cmsHandleKeyWithRepeat(pCurrentDisplay, key, repeatCount);
|
||||
|
||||
// Key repeat effect is implemented in two phases.
|
||||
// First phldase is to decrease rcDelayMs reciprocal to hold time.
|
||||
// When rcDelayMs reached a certain limit (scheduling interval),
|
||||
// repeat rate will not raise anymore, so we call key handler
|
||||
// multiple times (repeatCount).
|
||||
//
|
||||
// XXX Caveat: Most constants are adjusted pragmatically.
|
||||
// XXX Rewrite this someday, so it uses actual hold time instead
|
||||
// of holdCount, which depends on the scheduling interval.
|
||||
|
||||
if (((key == KEY_LEFT) || (key == KEY_RIGHT)) && (holdCount > 20)) {
|
||||
|
||||
// Decrease rcDelayMs reciprocally
|
||||
|
||||
rcDelayMs /= (holdCount - 20);
|
||||
|
||||
// When we reach the scheduling limit,
|
||||
|
||||
if (rcDelayMs <= 50) {
|
||||
|
||||
// start calling handler multiple times.
|
||||
|
||||
if (repeatBase == 0)
|
||||
repeatBase = holdCount;
|
||||
|
||||
if (holdCount < 100) {
|
||||
repeatCount = repeatCount + (holdCount - repeatBase) / 5;
|
||||
|
||||
if (repeatCount > 5) {
|
||||
repeatCount= 5;
|
||||
}
|
||||
} else {
|
||||
repeatCount = repeatCount + holdCount - repeatBase;
|
||||
|
||||
if (repeatCount > 50) {
|
||||
repeatCount = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rcDelayMs;
|
||||
}
|
||||
|
||||
void cmsUpdate(uint32_t currentTimeUs)
|
||||
{
|
||||
#ifdef USE_RCDEVICE
|
||||
|
@ -1116,126 +1187,35 @@ void cmsUpdate(uint32_t currentTimeUs)
|
|||
#endif
|
||||
|
||||
static int16_t rcDelayMs = BUTTON_TIME;
|
||||
static int holdCount = 1;
|
||||
static int repeatCount = 1;
|
||||
static int repeatBase = 0;
|
||||
// e.g #define CMS_INJECTED_KEYS KEY_DOWN,KEY_RIGHT,KEY_DOWN,KEY_RIGHT,KEY_DOWN
|
||||
#define CMS_INJECTED_KEYS_INTERVAL 800
|
||||
#if defined CMS_INJECTED_KEYS
|
||||
int cmsInjectedKeys[] = {KEY_NONE, CMS_INJECTED_KEYS};
|
||||
static timeMs_t lastInjectedKeyMs = 0;
|
||||
static unsigned lastInjectedKeyIndex = 0;
|
||||
#endif
|
||||
|
||||
static uint32_t lastCalledMs = 0;
|
||||
static timeMs_t lastCalledMs = 0;
|
||||
static uint32_t lastCmsHeartBeatMs = 0;
|
||||
|
||||
const uint32_t currentTimeMs = currentTimeUs / 1000;
|
||||
const timeMs_t currentTimeMs = currentTimeUs / 1000;
|
||||
|
||||
if (!cmsInMenu) {
|
||||
// Detect menu invocation
|
||||
#if defined(CMS_INJECTED_KEYS)
|
||||
cmsMenuOpen();
|
||||
rcDelayMs = 0;
|
||||
#else
|
||||
if (IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) && !ARMING_FLAG(ARMED)) {
|
||||
cmsMenuOpen();
|
||||
rcDelayMs = BUTTON_PAUSE; // Tends to overshoot if BUTTON_TIME
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//
|
||||
// Scan 'key' first
|
||||
//
|
||||
|
||||
uint8_t key = KEY_NONE;
|
||||
|
||||
if (IS_MID(THROTTLE) && IS_LO(YAW) && IS_HI(PITCH) && !ARMING_FLAG(ARMED)) {
|
||||
key = KEY_MENU;
|
||||
}
|
||||
else if (IS_HI(PITCH)) {
|
||||
key = KEY_UP;
|
||||
}
|
||||
else if (IS_LO(PITCH)) {
|
||||
key = KEY_DOWN;
|
||||
}
|
||||
else if (IS_LO(ROLL)) {
|
||||
key = KEY_LEFT;
|
||||
}
|
||||
else if (IS_HI(ROLL)) {
|
||||
key = KEY_RIGHT;
|
||||
}
|
||||
else if (IS_HI(YAW) || IS_LO(YAW))
|
||||
{
|
||||
key = KEY_ESC;
|
||||
// Check if we're yielding and its's time to stop it
|
||||
if (cmsYieldUntil > 0 && currentTimeMs > cmsYieldUntil) {
|
||||
cmsYieldUntil = 0;
|
||||
displayGrab(pCurrentDisplay);
|
||||
displayClearScreen(pCurrentDisplay);
|
||||
}
|
||||
|
||||
#if defined(CMS_INJECTED_KEYS)
|
||||
if (lastInjectedKeyMs < currentTimeMs - CMS_INJECTED_KEYS_INTERVAL) {
|
||||
if (lastInjectedKeyIndex < ARRAYLEN(cmsInjectedKeys)) {
|
||||
key = cmsInjectedKeys[lastInjectedKeyIndex++];
|
||||
lastInjectedKeyMs = currentTimeMs;
|
||||
// Only scan keys and draw if we're not yielding
|
||||
if (cmsYieldUntil == 0) {
|
||||
rcDelayMs = cmsScanKeys(currentTimeMs, lastCalledMs, rcDelayMs);
|
||||
// Check again, the keypress might have produced a yield
|
||||
if (cmsYieldUntil == 0) {
|
||||
cmsDrawMenu(pCurrentDisplay, currentTimeUs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (key == KEY_NONE) {
|
||||
// No 'key' pressed, reset repeat control
|
||||
holdCount = 1;
|
||||
repeatCount = 1;
|
||||
repeatBase = 0;
|
||||
} else {
|
||||
// The 'key' is being pressed; keep counting
|
||||
++holdCount;
|
||||
}
|
||||
|
||||
if (rcDelayMs > 0) {
|
||||
rcDelayMs -= (currentTimeMs - lastCalledMs);
|
||||
} else if (key) {
|
||||
rcDelayMs = cmsHandleKeyWithRepeat(pCurrentDisplay, key, repeatCount);
|
||||
|
||||
// Key repeat effect is implemented in two phases.
|
||||
// First phldase is to decrease rcDelayMs reciprocal to hold time.
|
||||
// When rcDelayMs reached a certain limit (scheduling interval),
|
||||
// repeat rate will not raise anymore, so we call key handler
|
||||
// multiple times (repeatCount).
|
||||
//
|
||||
// XXX Caveat: Most constants are adjusted pragmatically.
|
||||
// XXX Rewrite this someday, so it uses actual hold time instead
|
||||
// of holdCount, which depends on the scheduling interval.
|
||||
|
||||
if (((key == KEY_LEFT) || (key == KEY_RIGHT)) && (holdCount > 20)) {
|
||||
|
||||
// Decrease rcDelayMs reciprocally
|
||||
|
||||
rcDelayMs /= (holdCount - 20);
|
||||
|
||||
// When we reach the scheduling limit,
|
||||
|
||||
if (rcDelayMs <= 50) {
|
||||
|
||||
// start calling handler multiple times.
|
||||
|
||||
if (repeatBase == 0)
|
||||
repeatBase = holdCount;
|
||||
|
||||
if (holdCount < 100) {
|
||||
repeatCount = repeatCount + (holdCount - repeatBase) / 5;
|
||||
|
||||
if (repeatCount > 5) {
|
||||
repeatCount= 5;
|
||||
}
|
||||
} else {
|
||||
repeatCount = repeatCount + holdCount - repeatBase;
|
||||
|
||||
if (repeatCount > 50) {
|
||||
repeatCount= 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmsDrawMenu(pCurrentDisplay, currentTimeUs);
|
||||
|
||||
if (currentTimeMs > lastCmsHeartBeatMs + 500) {
|
||||
// Heart beat for external CMS display device @ 500msec
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "common/time.h"
|
||||
|
||||
#include "cms/cms_types.h"
|
||||
|
||||
extern bool cmsInMenu;
|
||||
|
||||
// Device management
|
||||
|
@ -13,8 +15,9 @@ bool cmsDisplayPortRegister(displayPort_t *pDisplay);
|
|||
void cmsInit(void);
|
||||
void cmsHandler(timeUs_t currentTimeUs);
|
||||
|
||||
long cmsMenuChange(displayPort_t *pPort, const void *ptr);
|
||||
long cmsMenuChange(displayPort_t *pPort, const CMS_Menu *menu, const OSD_Entry *from);
|
||||
long cmsMenuExit(displayPort_t *pPort, const void *ptr);
|
||||
void cmsYieldDisplay(displayPort_t *pPort, timeMs_t duration);
|
||||
void cmsUpdate(uint32_t currentTimeUs);
|
||||
|
||||
#define CMS_STARTUP_HELP_TEXT1 "MENU: THR MID"
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "build/version.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "drivers/time.h"
|
||||
|
||||
#include "cms/cms.h"
|
||||
|
@ -59,8 +61,10 @@ static char infoTargetName[] = __TARGET__;
|
|||
|
||||
#include "msp/msp_protocol.h" // XXX for FC identification... not available elsewhere
|
||||
|
||||
static long cmsx_InfoInit(void)
|
||||
static long cmsx_InfoInit(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
int i;
|
||||
for ( i = 0 ; i < GIT_SHORT_REVISION_LENGTH ; i++) {
|
||||
if (shortGitRevision[i] >= 'a' && shortGitRevision[i] <= 'f')
|
||||
|
@ -142,8 +146,8 @@ static const OSD_Entry menuMainEntries[] =
|
|||
|
||||
OSD_SUBMENU_ENTRY("PID TUNING", &cmsx_menuImu),
|
||||
OSD_SUBMENU_ENTRY("FEATURES", &menuFeatures),
|
||||
#ifdef USE_OSD
|
||||
OSD_SUBMENU_ENTRY("SCR LAYOUT", &cmsx_menuOsdLayout),
|
||||
#if defined(USE_OSD) && defined(CMS_MENU_OSD)
|
||||
OSD_SUBMENU_ENTRY("OSD LAYOUTS", &cmsx_menuOsdLayout),
|
||||
OSD_SUBMENU_ENTRY("ALARMS", &cmsx_menuAlarms),
|
||||
#endif
|
||||
OSD_SUBMENU_ENTRY("FC&FW INFO", &menuInfo),
|
||||
|
|
|
@ -66,8 +66,10 @@ static void cmsx_WritebackPidFromArray(uint8_t *src, int pidIndex)
|
|||
pidBankMutable()->pid[pidIndex].D = src[2];
|
||||
}
|
||||
|
||||
static long cmsx_menuImu_onEnter(void)
|
||||
static long cmsx_menuImu_onEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
profileIndex = getConfigProfile();
|
||||
tmpProfileIndex = profileIndex + 1;
|
||||
profileIndexString[1] = '0' + tmpProfileIndex;
|
||||
|
@ -108,8 +110,10 @@ static long cmsx_PidRead(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long cmsx_PidOnEnter(void)
|
||||
static long cmsx_PidOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
profileIndexString[1] = '0' + tmpProfileIndex;
|
||||
cmsx_PidRead();
|
||||
|
||||
|
@ -164,8 +168,10 @@ static uint8_t cmsx_pidPosZ[3];
|
|||
static uint8_t cmsx_pidVelZ[3];
|
||||
static uint8_t cmsx_pidHead[3];
|
||||
|
||||
static long cmsx_menuPidAltMag_onEnter(void)
|
||||
static long cmsx_menuPidAltMag_onEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
cmsx_ReadPidToArray(cmsx_pidPosZ, PID_POS_Z);
|
||||
cmsx_ReadPidToArray(cmsx_pidVelZ, PID_VEL_Z);
|
||||
cmsx_pidHead[0] = pidBank()->pid[PID_HEADING].P;
|
||||
|
@ -217,8 +223,10 @@ static const CMS_Menu cmsx_menuPidAltMag = {
|
|||
static uint8_t cmsx_pidPosXY[3];
|
||||
static uint8_t cmsx_pidVelXY[3];
|
||||
|
||||
static long cmsx_menuPidGpsnav_onEnter(void)
|
||||
static long cmsx_menuPidGpsnav_onEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
cmsx_ReadPidToArray(cmsx_pidPosXY, PID_POS_XY);
|
||||
cmsx_ReadPidToArray(cmsx_pidVelXY, PID_VEL_XY);
|
||||
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(USE_OSD) && defined(USE_CMS)
|
||||
#if defined(USE_OSD) && defined(USE_CMS) && defined(CMS_MENU_OSD)
|
||||
|
||||
#include "build/debug.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
|
@ -33,8 +35,21 @@
|
|||
|
||||
#include "io/osd.h"
|
||||
|
||||
static const OSD_Entry cmsx_menuAlarmsEntries[] =
|
||||
{
|
||||
#define OSD_ITEM_ENTRY(label, item_id) ((OSD_Entry){ label, OME_Submenu, (void *)item_id, &cmsx_menuOsdElementActions, 0 })
|
||||
#define OSD_ITEM_GET_ID(entry) ((int)entry->func)
|
||||
|
||||
static int osdCurrentLayout = -1;
|
||||
static int osdCurrentItem = -1;
|
||||
|
||||
static uint8_t osdCurrentElementRow = 0;
|
||||
static uint8_t osdCurrentElementColumn = 0;
|
||||
static uint8_t osdCurrentElementVisible = 0;
|
||||
|
||||
static long osdElementsOnEnter(const OSD_Entry *from);
|
||||
static long osdElementsOnExit(const OSD_Entry *from);
|
||||
static long osdElemActionsOnEnter(const OSD_Entry *from);
|
||||
|
||||
static const OSD_Entry cmsx_menuAlarmsEntries[] = {
|
||||
OSD_LABEL_ENTRY("--- ALARMS ---"),
|
||||
|
||||
OSD_SETTING_ENTRY_STEP("RSSI", SETTING_OSD_RSSI_ALARM, 5),
|
||||
|
@ -56,62 +71,167 @@ const CMS_Menu cmsx_menuAlarms = {
|
|||
.entries = cmsx_menuAlarmsEntries,
|
||||
};
|
||||
|
||||
|
||||
#define OSD_OSD_ELEMENT_ENTRY(name, osd_item_id) {name, OME_VISIBLE, NULL, (void *)osd_item_id, 0}
|
||||
|
||||
static const OSD_Entry menuOsdActiveElemsEntries[] =
|
||||
static long cmsx_osdElementOnChange(displayPort_t *displayPort, const void *ptr)
|
||||
{
|
||||
OSD_LABEL_ENTRY("--- ACTIV ELEM ---"),
|
||||
UNUSED(ptr);
|
||||
|
||||
OSD_OSD_ELEMENT_ENTRY("RSSI", OSD_RSSI_VALUE),
|
||||
OSD_OSD_ELEMENT_ENTRY("MAIN BATTERY", OSD_MAIN_BATT_VOLTAGE),
|
||||
OSD_OSD_ELEMENT_ENTRY("HORIZON", OSD_ARTIFICIAL_HORIZON),
|
||||
OSD_OSD_ELEMENT_ENTRY("HORIZON SIDEBARS", OSD_HORIZON_SIDEBARS),
|
||||
OSD_OSD_ELEMENT_ENTRY("UPTIME", OSD_ONTIME),
|
||||
OSD_OSD_ELEMENT_ENTRY("FLY TIME", OSD_FLYTIME),
|
||||
OSD_OSD_ELEMENT_ENTRY("FLY MODE", OSD_FLYMODE),
|
||||
OSD_OSD_ELEMENT_ENTRY("NAME", OSD_CRAFT_NAME),
|
||||
OSD_OSD_ELEMENT_ENTRY("THROTTLE", OSD_THROTTLE_POS),
|
||||
#ifdef VTX
|
||||
OSD_OSD_ELEMENT_ENTRY("VTX CHAN", OSD_VTX_CHANNEL),
|
||||
#endif // VTX
|
||||
OSD_OSD_ELEMENT_ENTRY("CURRENT (A)", OSD_CURRENT_DRAW),
|
||||
OSD_OSD_ELEMENT_ENTRY("USED MAH", OSD_MAH_DRAWN),
|
||||
#ifdef USE_GPS
|
||||
OSD_OSD_ELEMENT_ENTRY("HOME DIR.", OSD_HOME_DIR),
|
||||
OSD_OSD_ELEMENT_ENTRY("HOME DIST.", OSD_HOME_DIST),
|
||||
OSD_OSD_ELEMENT_ENTRY("GPS SPEED", OSD_GPS_SPEED),
|
||||
OSD_OSD_ELEMENT_ENTRY("GPS SATS.", OSD_GPS_SATS),
|
||||
OSD_OSD_ELEMENT_ENTRY("GPS LAT", OSD_GPS_LAT),
|
||||
OSD_OSD_ELEMENT_ENTRY("GPS LON.", OSD_GPS_LON),
|
||||
OSD_OSD_ELEMENT_ENTRY("HEADING", OSD_HEADING),
|
||||
#endif // GPS
|
||||
#if defined(USE_BARO) || defined(USE_GPS)
|
||||
OSD_OSD_ELEMENT_ENTRY("VARIO", OSD_VARIO),
|
||||
OSD_OSD_ELEMENT_ENTRY("VARIO NUM", OSD_VARIO_NUM),
|
||||
#endif // defined
|
||||
OSD_OSD_ELEMENT_ENTRY("ALTITUDE", OSD_ALTITUDE),
|
||||
OSD_OSD_ELEMENT_ENTRY("AIR SPEED", OSD_AIR_SPEED),
|
||||
uint16_t *pos = &osdConfigMutable()->item_pos[osdCurrentLayout][osdCurrentItem];
|
||||
*pos = OSD_POS(osdCurrentElementColumn, osdCurrentElementRow);
|
||||
if (osdCurrentElementVisible) {
|
||||
*pos |= OSD_VISIBLE_FLAG;
|
||||
}
|
||||
cmsYieldDisplay(displayPort, 500);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long osdElementPreview(displayPort_t *displayPort, const void *ptr)
|
||||
{
|
||||
UNUSED(ptr);
|
||||
|
||||
cmsYieldDisplay(displayPort, 2000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const OSD_Entry menuOsdElemActionsEntries[] = {
|
||||
|
||||
OSD_BOOL_CALLBACK_ENTRY("ENABLED", cmsx_osdElementOnChange, &osdCurrentElementVisible),
|
||||
OSD_UINT8_CALLBACK_ENTRY("ROW", cmsx_osdElementOnChange, (&(const OSD_UINT8_t){ &osdCurrentElementRow, 0, OSD_X(OSD_POS_MAX), 1 })),
|
||||
OSD_UINT8_CALLBACK_ENTRY("COLUMN", cmsx_osdElementOnChange, (&(const OSD_UINT8_t){ &osdCurrentElementColumn, 0, OSD_Y(OSD_POS_MAX), 1 })),
|
||||
OSD_FUNC_CALL_ENTRY("PREVIEW", osdElementPreview),
|
||||
|
||||
OSD_BACK_ENTRY,
|
||||
OSD_END_ENTRY,
|
||||
};
|
||||
|
||||
const CMS_Menu menuOsdActiveElems = {
|
||||
static const OSD_Entry menuOsdFixedElemActionsEntries[] = {
|
||||
|
||||
OSD_BOOL_CALLBACK_ENTRY("ENABLED", cmsx_osdElementOnChange, &osdCurrentElementVisible),
|
||||
OSD_FUNC_CALL_ENTRY("PREVIEW", osdElementPreview),
|
||||
|
||||
OSD_BACK_ENTRY,
|
||||
OSD_END_ENTRY,
|
||||
};
|
||||
|
||||
static CMS_Menu cmsx_menuOsdElementActions = {
|
||||
#ifdef CMS_MENU_DEBUG
|
||||
.GUARD_text = "MENUOSDACT",
|
||||
.GUARD_text = "MENUOSDELEM",
|
||||
.GUARD_type = OME_MENU,
|
||||
#endif
|
||||
.onEnter = NULL,
|
||||
.onEnter = osdElemActionsOnEnter,
|
||||
.onExit = NULL,
|
||||
.onGlobalExit = NULL,
|
||||
.entries = menuOsdActiveElemsEntries
|
||||
.entries = menuOsdElemActionsEntries,
|
||||
};
|
||||
|
||||
static long osdElemActionsOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
osdCurrentItem = OSD_ITEM_GET_ID(from);
|
||||
uint16_t pos = osdConfig()->item_pos[osdCurrentLayout][osdCurrentItem];
|
||||
osdCurrentElementColumn = OSD_X(pos);
|
||||
osdCurrentElementRow = OSD_Y(pos);
|
||||
osdCurrentElementVisible = OSD_VISIBLE(pos) ? 1 : 0;
|
||||
if (osdItemIsFixed(osdCurrentItem)) {
|
||||
cmsx_menuOsdElementActions.entries = menuOsdFixedElemActionsEntries;
|
||||
} else {
|
||||
cmsx_menuOsdElementActions.entries = menuOsdElemActionsEntries;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OSD_ELEMENT_ENTRY(name, osd_item_id) OSD_ITEM_ENTRY(name, osd_item_id)
|
||||
|
||||
static const OSD_Entry menuOsdElemsEntries[] =
|
||||
{
|
||||
OSD_LABEL_ENTRY("--- OSD ---"),
|
||||
|
||||
OSD_ELEMENT_ENTRY("RSSI", OSD_RSSI_VALUE),
|
||||
OSD_ELEMENT_ENTRY("MAIN BATTERY", OSD_MAIN_BATT_VOLTAGE),
|
||||
OSD_ELEMENT_ENTRY("CELL VOLTAGE", OSD_MAIN_BATT_CELL_VOLTAGE),
|
||||
OSD_ELEMENT_ENTRY("CROSSHAIRS", OSD_CROSSHAIRS),
|
||||
OSD_ELEMENT_ENTRY("HORIZON", OSD_ARTIFICIAL_HORIZON),
|
||||
OSD_ELEMENT_ENTRY("HORIZON SIDEBARS", OSD_HORIZON_SIDEBARS),
|
||||
OSD_ELEMENT_ENTRY("ON TIME", OSD_ONTIME),
|
||||
OSD_ELEMENT_ENTRY("FLY TIME", OSD_FLYTIME),
|
||||
OSD_ELEMENT_ENTRY("ON/FLY TIME", OSD_ONTIME_FLYTIME),
|
||||
OSD_ELEMENT_ENTRY("TIME (HOUR)", OSD_RTC_TIME),
|
||||
OSD_ELEMENT_ENTRY("FLY MODE", OSD_FLYMODE),
|
||||
OSD_ELEMENT_ENTRY("NAME", OSD_CRAFT_NAME),
|
||||
OSD_ELEMENT_ENTRY("THR. (MANU)", OSD_THROTTLE_POS),
|
||||
OSD_ELEMENT_ENTRY("THR. (MANU/AUTO)", OSD_THROTTLE_POS_AUTO_THR),
|
||||
OSD_ELEMENT_ENTRY("SYS MESSAGES", OSD_MESSAGES),
|
||||
#ifdef VTX_COMMON
|
||||
OSD_ELEMENT_ENTRY("VTX CHAN", OSD_VTX_CHANNEL),
|
||||
#endif // VTX
|
||||
OSD_ELEMENT_ENTRY("CURRENT (A)", OSD_CURRENT_DRAW),
|
||||
OSD_ELEMENT_ENTRY("POWER", OSD_POWER),
|
||||
OSD_ELEMENT_ENTRY("USED MAH", OSD_MAH_DRAWN),
|
||||
OSD_ELEMENT_ENTRY("USED WH", OSD_WH_DRAWN),
|
||||
OSD_ELEMENT_ENTRY("EFF/KM (AH)", OSD_EFFICIENCY_MAH_PER_KM),
|
||||
OSD_ELEMENT_ENTRY("EFF/KM (WH)", OSD_EFFICIENCY_WH_PER_KM),
|
||||
OSD_ELEMENT_ENTRY("BATT CAP REM", OSD_BATTERY_REMAINING_CAPACITY),
|
||||
OSD_ELEMENT_ENTRY("BATT % REM", OSD_BATTERY_REMAINING_PERCENT),
|
||||
#ifdef USE_GPS
|
||||
OSD_ELEMENT_ENTRY("HOME DIR", OSD_HOME_DIR),
|
||||
OSD_ELEMENT_ENTRY("HOME DIST", OSD_HOME_DIST),
|
||||
OSD_ELEMENT_ENTRY("TRIP DIST", OSD_TRIP_DIST),
|
||||
OSD_ELEMENT_ENTRY("GPS SPEED", OSD_GPS_SPEED),
|
||||
OSD_ELEMENT_ENTRY("GPS SATS", OSD_GPS_SATS),
|
||||
OSD_ELEMENT_ENTRY("GPS LAT", OSD_GPS_LAT),
|
||||
OSD_ELEMENT_ENTRY("GPS LON", OSD_GPS_LON),
|
||||
OSD_ELEMENT_ENTRY("GPS HDOP", OSD_GPS_HDOP),
|
||||
#endif // GPS
|
||||
OSD_ELEMENT_ENTRY("HEADING", OSD_HEADING),
|
||||
OSD_ELEMENT_ENTRY("HEADING GR.", OSD_HEADING_GRAPH),
|
||||
#if defined(USE_BARO) || defined(USE_GPS)
|
||||
OSD_ELEMENT_ENTRY("VARIO", OSD_VARIO),
|
||||
OSD_ELEMENT_ENTRY("VARIO NUM", OSD_VARIO_NUM),
|
||||
#endif // defined
|
||||
OSD_ELEMENT_ENTRY("ALTITUDE", OSD_ALTITUDE),
|
||||
#if defined(USE_PITOT)
|
||||
OSD_ELEMENT_ENTRY("AIR SPEED", OSD_AIR_SPEED),
|
||||
#endif
|
||||
OSD_ELEMENT_ENTRY("ROLL PIDS", OSD_ROLL_PIDS),
|
||||
OSD_ELEMENT_ENTRY("PITCH PIDS", OSD_PITCH_PIDS),
|
||||
OSD_ELEMENT_ENTRY("YAW PIDS", OSD_YAW_PIDS),
|
||||
|
||||
OSD_BACK_ENTRY,
|
||||
OSD_END_ENTRY,
|
||||
};
|
||||
|
||||
#if defined(VTX_COMMON) && defined(USE_GPS) && defined(USE_BARO) && defined(USE_PITOT)
|
||||
// All CMS OSD elements should be enabled in this case
|
||||
_Static_assert(ARRAYLEN(menuOsdElemsEntries) - 3 == OSD_ITEM_COUNT, "missing OSD elements in CMS");
|
||||
#endif
|
||||
|
||||
const CMS_Menu menuOsdElements = {
|
||||
#ifdef CMS_MENU_DEBUG
|
||||
.GUARD_text = "MENUOSDELEMS",
|
||||
.GUARD_type = OME_MENU,
|
||||
#endif
|
||||
.onEnter = osdElementsOnEnter,
|
||||
.onExit = osdElementsOnExit,
|
||||
.onGlobalExit = NULL,
|
||||
.entries = menuOsdElemsEntries,
|
||||
};
|
||||
|
||||
|
||||
#define OSD_LAYOUT_SUBMENU_ENTRY(label) OSD_SUBMENU_ENTRY(label, &menuOsdElements)
|
||||
|
||||
static const OSD_Entry cmsx_menuOsdLayoutEntries[] =
|
||||
{
|
||||
OSD_LABEL_ENTRY("---SCREEN LAYOUT---"),
|
||||
OSD_SUBMENU_ENTRY("ACTIVE ELEM", &menuOsdActiveElems),
|
||||
|
||||
OSD_LAYOUT_SUBMENU_ENTRY("DEFAULT"),
|
||||
#if OSD_ALTERNATE_LAYOUT_COUNT > 0
|
||||
OSD_LAYOUT_SUBMENU_ENTRY("ALTERNATE 1"),
|
||||
#if OSD_ALTERNATE_LAYOUT_COUNT > 1
|
||||
OSD_LAYOUT_SUBMENU_ENTRY("ALTERNATE 2"),
|
||||
#if OSD_ALTERNATE_LAYOUT_COUNT > 2
|
||||
OSD_LAYOUT_SUBMENU_ENTRY("ALTERNATE 3"),
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
OSD_BACK_ENTRY,
|
||||
OSD_END_ENTRY,
|
||||
|
@ -125,6 +245,25 @@ const CMS_Menu cmsx_menuOsdLayout = {
|
|||
.onEnter = NULL,
|
||||
.onExit = NULL,
|
||||
.onGlobalExit = NULL,
|
||||
.entries = cmsx_menuOsdLayoutEntries
|
||||
.entries = cmsx_menuOsdLayoutEntries,
|
||||
};
|
||||
|
||||
static long osdElementsOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
// First entry is the label. Store the current layout
|
||||
// and override it on the OSD so previews so this layout.
|
||||
osdCurrentLayout = from - cmsx_menuOsdLayoutEntries - 1;
|
||||
osdOverrideLayout(osdCurrentLayout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long osdElementsOnExit(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
// Stop overriding OSD layout
|
||||
osdOverrideLayout(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // CMS
|
||||
|
|
|
@ -365,7 +365,7 @@ static const char * const saCmsPitFModeNames[] = {
|
|||
|
||||
static const OSD_TAB_t saCmsEntPitFMode = { &saCmsPitFMode, 1, saCmsPitFModeNames };
|
||||
|
||||
static long sacms_SetupTopMenu(void); // Forward
|
||||
static long sacms_SetupTopMenu(const OSD_Entry *from); // Forward
|
||||
|
||||
static long saCmsConfigFreqModeByGvar(displayPort_t *pDisp, const void *self)
|
||||
{
|
||||
|
@ -385,7 +385,7 @@ static long saCmsConfigFreqModeByGvar(displayPort_t *pDisp, const void *self)
|
|||
}
|
||||
}
|
||||
|
||||
sacms_SetupTopMenu();
|
||||
sacms_SetupTopMenu(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -421,8 +421,10 @@ static long saCmsCommence(displayPort_t *pDisp, const void *self)
|
|||
return MENU_CHAIN_BACK;
|
||||
}
|
||||
|
||||
static long saCmsSetPORFreqOnEnter(void)
|
||||
static long saCmsSetPORFreqOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
saCmsORFreqNew = saCmsORFreq;
|
||||
|
||||
return 0;
|
||||
|
@ -456,8 +458,10 @@ static char *saCmsUserFreqGetString(void)
|
|||
return pbuf;
|
||||
}
|
||||
|
||||
static long saCmsSetUserFreqOnEnter(void)
|
||||
static long saCmsSetUserFreqOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
saCmsUserFreqNew = saCmsUserFreq;
|
||||
|
||||
return 0;
|
||||
|
@ -612,8 +616,10 @@ static const OSD_Entry saCmsMenuOfflineEntries[] =
|
|||
|
||||
CMS_Menu cmsx_menuVtxSmartAudio; // Forward
|
||||
|
||||
static long sacms_SetupTopMenu(void)
|
||||
static long sacms_SetupTopMenu(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
if (saCmsDeviceStatus) {
|
||||
if (saCmsFselMode == 0)
|
||||
cmsx_menuVtxSmartAudio.entries = saCmsMenuChanModeEntries;
|
||||
|
|
|
@ -186,8 +186,10 @@ static void trampCmsInitSettings(void)
|
|||
}
|
||||
}
|
||||
|
||||
static long trampCmsOnEnter(void)
|
||||
static long trampCmsOnEnter(const OSD_Entry *from)
|
||||
{
|
||||
UNUSED(from);
|
||||
|
||||
trampCmsInitSettings();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -46,9 +46,6 @@ typedef enum
|
|||
OME_FLOAT, //only up to 255 value and cant be 2.55 or 25.5, just for PID's
|
||||
OME_Setting,
|
||||
//wlasciwosci elementow
|
||||
#ifdef USE_OSD
|
||||
OME_VISIBLE,
|
||||
#endif
|
||||
OME_TAB,
|
||||
OME_END,
|
||||
|
||||
|
@ -81,9 +78,10 @@ typedef struct
|
|||
#define OSD_LABEL_DATA_DYN_ENTRY(label, data) ((OSD_Entry){ label, OME_Label, NULL, data, DYNAMIC })
|
||||
#define OSD_LABEL_FUNC_DYN_ENTRY(label, fn) ((OSD_Entry){ label, OME_LabelFunc, NULL, fn, DYNAMIC })
|
||||
#define OSD_BACK_ENTRY ((OSD_Entry){ "BACK", OME_Back, NULL, NULL, 0 })
|
||||
#define OSD_SUBMENU_ENTRY(label, menu) ((OSD_Entry){ label, OME_Submenu, cmsMenuChange, menu, 0 })
|
||||
#define OSD_SUBMENU_ENTRY(label, menu) ((OSD_Entry){ label, OME_Submenu, NULL, menu, 0 })
|
||||
#define OSD_FUNC_CALL_ENTRY(label, fn) ((OSD_Entry){ label, OME_Funcall, fn, NULL, 0 })
|
||||
#define OSD_BOOL_ENTRY(label, val) ((OSD_Entry){ label, OME_Bool, NULL, val, 0 })
|
||||
#define OSD_BOOL_CALLBACK_ENTRY(label, cb, val) ((OSD_Entry){ label, OME_Bool, cb, val, 0 })
|
||||
#define OSD_BOOL_FUNC_ENTRY(label, fn) ((OSD_Entry){ label, OME_BoolFunc, NULL, fn, 0 })
|
||||
#define OSD_UINT8_ENTRY(label, val) ((OSD_Entry){ label, OME_UINT8, NULL, val, 0 })
|
||||
#define OSD_UINT8_CALLBACK_ENTRY(label, cb, val)((OSD_Entry){ label, OME_UINT8, cb, val, 0 })
|
||||
|
@ -109,7 +107,7 @@ typedef enum {
|
|||
// Use a function and data type to make sure switches are exhaustive
|
||||
static inline CMSDataType_e CMS_DATA_TYPE(const OSD_Entry *entry) { return entry->flags & 0xF0; }
|
||||
|
||||
typedef long (*CMSMenuFuncPtr)(void);
|
||||
typedef long (*CMSMenuFuncPtr)(const OSD_Entry *from);
|
||||
|
||||
// Special return value(s) for function chaining by CMSMenuFuncPtr
|
||||
#define MENU_CHAIN_BACK (-1) // Causes automatic cmsMenuBack
|
||||
|
|
|
@ -1643,6 +1643,127 @@ static void cliFlashRead(char *cmdline)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_OSD
|
||||
static void printOsdLayout(uint8_t dumpMask, const osdConfig_t *osdConfig, const osdConfig_t *osdConfigDefault, int layout, int item)
|
||||
{
|
||||
// "<layout> <item> <col> <row> <visible>"
|
||||
const char *format = "osd_layout %d %d %d %d %c";
|
||||
for (int ii = 0; ii < OSD_LAYOUT_COUNT; ii++) {
|
||||
if (layout >= 0 && layout != ii) {
|
||||
continue;
|
||||
}
|
||||
const uint16_t *layoutItems = osdConfig->item_pos[ii];
|
||||
const uint16_t *defaultLayoutItems = osdConfigDefault->item_pos[ii];
|
||||
for (int jj = 0; jj < OSD_ITEM_COUNT; jj++) {
|
||||
if (item >= 0 && item != jj) {
|
||||
continue;
|
||||
}
|
||||
bool equalsDefault = layoutItems[jj] == defaultLayoutItems[jj];
|
||||
cliDefaultPrintLinef(dumpMask, equalsDefault, format,
|
||||
ii, jj,
|
||||
OSD_X(defaultLayoutItems[jj]),
|
||||
OSD_Y(defaultLayoutItems[jj]),
|
||||
OSD_VISIBLE(defaultLayoutItems[jj]) ? 'V' : 'H');
|
||||
|
||||
cliDumpPrintLinef(dumpMask, equalsDefault, format,
|
||||
ii, jj,
|
||||
OSD_X(layoutItems[jj]),
|
||||
OSD_Y(layoutItems[jj]),
|
||||
OSD_VISIBLE(layoutItems[jj]) ? 'V' : 'H');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cliOsdLayout(char *cmdline)
|
||||
{
|
||||
char * saveptr;
|
||||
|
||||
int layout = -1;
|
||||
int item = -1;
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
bool visible = false;
|
||||
char *tok = strtok_r(cmdline, " ", &saveptr);
|
||||
|
||||
int ii;
|
||||
|
||||
for (ii = 0; tok != NULL; ii++, tok = strtok_r(NULL, " ", &saveptr)) {
|
||||
switch (ii) {
|
||||
case 0:
|
||||
layout = fastA2I(tok);
|
||||
if (layout < 0 || layout >= OSD_LAYOUT_COUNT) {
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
item = fastA2I(tok);
|
||||
if (item < 0 || item >= OSD_ITEM_COUNT) {
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
col = fastA2I(tok);
|
||||
if (col < 0 || col > OSD_X(OSD_POS_MAX)) {
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
row = fastA2I(tok);
|
||||
if (row < 0 || row > OSD_Y(OSD_POS_MAX)) {
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (*tok) {
|
||||
case 'H':
|
||||
visible = false;
|
||||
break;
|
||||
case 'V':
|
||||
visible = true;
|
||||
break;
|
||||
default:
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ii) {
|
||||
case 0:
|
||||
FALLTHROUGH;
|
||||
case 1:
|
||||
FALLTHROUGH;
|
||||
case 2:
|
||||
// No args, or just layout or layout and item. If any of them not provided,
|
||||
// it will be the -1 that we used during initialization, so printOsdLayout()
|
||||
// won't use them for filtering.
|
||||
printOsdLayout(DUMP_MASTER, osdConfig(), osdConfig(), layout, item);
|
||||
break;
|
||||
case 4:
|
||||
// No visibility provided. Keep the previous one.
|
||||
visible = OSD_VISIBLE(osdConfig()->item_pos[layout][item]);
|
||||
FALLTHROUGH;
|
||||
case 5:
|
||||
// Layout, item, pos and visibility. Set the item.
|
||||
osdConfigMutable()->item_pos[layout][item] = OSD_POS(col, row) | (visible ? OSD_VISIBLE_FLAG : 0);
|
||||
break;
|
||||
default:
|
||||
// Unhandled
|
||||
cliShowParseError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void printFeature(uint8_t dumpMask, const featureConfig_t *featureConfig, const featureConfig_t *featureConfigDefault)
|
||||
{
|
||||
uint32_t mask = featureConfig->enabledFeatures;
|
||||
|
@ -2541,6 +2662,11 @@ static void printConfig(const char *cmdline, bool doDiff)
|
|||
cliPrintHashLine("rxrange");
|
||||
printRxRange(dumpMask, rxChannelRangeConfigs_CopyArray, rxChannelRangeConfigs(0));
|
||||
|
||||
#ifdef USE_OSD
|
||||
cliPrintHashLine("osd_layout");
|
||||
printOsdLayout(dumpMask, &osdConfig_Copy, osdConfig(), -1, -1);
|
||||
#endif
|
||||
|
||||
cliPrintHashLine("master");
|
||||
dumpAllValues(MASTER_VALUE, dumpMask);
|
||||
|
||||
|
@ -2685,6 +2811,9 @@ const clicmd_t cmdTable[] = {
|
|||
CLI_COMMAND_DEF("tasks", "show task stats", NULL, cliTasks),
|
||||
#endif
|
||||
CLI_COMMAND_DEF("version", "show version", NULL, cliVersion),
|
||||
#ifdef USE_OSD
|
||||
CLI_COMMAND_DEF("osd_layout", "get or set the layout of OSD items", "[<layout> [<item> [<col> <row> [<visible>]]]]", cliOsdLayout),
|
||||
#endif
|
||||
};
|
||||
|
||||
static void cliHelp(char *cmdline)
|
||||
|
|
|
@ -968,7 +968,7 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
|
|||
sbufWriteU16(dst, osdConfig()->dist_alarm);
|
||||
sbufWriteU16(dst, osdConfig()->neg_alt_alarm);
|
||||
for (int i = 0; i < OSD_ITEM_COUNT; i++) {
|
||||
sbufWriteU16(dst, osdConfig()->item_pos[i]);
|
||||
sbufWriteU16(dst, osdConfig()->item_pos[0][i]);
|
||||
}
|
||||
#else
|
||||
sbufWriteU8(dst, 0); // OSD not supported
|
||||
|
@ -1305,6 +1305,38 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
|
|||
sbufWriteU8(dst, MAX_SUPPORTED_SERVOS);
|
||||
break;
|
||||
|
||||
#if defined(USE_OSD)
|
||||
case MSP2_INAV_OSD_LAYOUTS:
|
||||
sbufWriteU8(dst, OSD_LAYOUT_COUNT);
|
||||
sbufWriteU8(dst, OSD_ITEM_COUNT);
|
||||
for (unsigned ii = 0; ii < OSD_LAYOUT_COUNT; ii++) {
|
||||
for (unsigned jj = 0; jj < OSD_ITEM_COUNT; jj++) {
|
||||
sbufWriteU16(dst, osdConfig()->item_pos[ii][jj]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSP2_INAV_OSD_ALARMS:
|
||||
sbufWriteU8(dst, osdConfig()->rssi_alarm);
|
||||
sbufWriteU16(dst, osdConfig()->time_alarm);
|
||||
sbufWriteU16(dst, osdConfig()->alt_alarm);
|
||||
sbufWriteU16(dst, osdConfig()->dist_alarm);
|
||||
sbufWriteU16(dst, osdConfig()->neg_alt_alarm);
|
||||
break;
|
||||
|
||||
case MSP2_INAV_OSD_PREFERENCES:
|
||||
sbufWriteU8(dst, osdConfig()->video_system);
|
||||
sbufWriteU8(dst, osdConfig()->main_voltage_decimals);
|
||||
sbufWriteU8(dst, osdConfig()->ahi_reverse_roll);
|
||||
sbufWriteU8(dst, osdConfig()->crosshairs_style);
|
||||
sbufWriteU8(dst, osdConfig()->left_sidebar_scroll);
|
||||
sbufWriteU8(dst, osdConfig()->right_sidebar_scroll);
|
||||
sbufWriteU8(dst, osdConfig()->sidebar_scroll_arrows);
|
||||
sbufWriteU8(dst, osdConfig()->units);
|
||||
sbufWriteU8(dst, osdConfig()->stats_energy_unit);
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2018,7 +2050,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
|
|||
} else {
|
||||
// set a position setting
|
||||
if ((dataSize >= 3) && (tmp_u8 < OSD_ITEM_COUNT)) // tmp_u8 == addr
|
||||
osdConfigMutable()->item_pos[tmp_u8] = sbufReadU16(src);
|
||||
osdConfigMutable()->item_pos[0][tmp_u8] = sbufReadU16(src);
|
||||
else
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
|
@ -2389,6 +2421,52 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
|
|||
mixerUpdateStateFlags();
|
||||
break;
|
||||
|
||||
#if defined(USE_OSD)
|
||||
case MSP2_INAV_OSD_SET_LAYOUT_ITEM:
|
||||
{
|
||||
uint8_t layout;
|
||||
if (!sbufReadU8Safe(&layout, src)) {
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
uint8_t item;
|
||||
if (!sbufReadU8Safe(&item, src)) {
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
if (!sbufReadU16Safe(&osdConfigMutable()->item_pos[layout][item], src)) {
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
osdStartFullRedraw();
|
||||
}
|
||||
|
||||
break;
|
||||
case MSP2_INAV_OSD_SET_ALARMS:
|
||||
{
|
||||
sbufReadU8Safe(&osdConfigMutable()->rssi_alarm, src);
|
||||
sbufReadU16Safe(&osdConfigMutable()->time_alarm, src);
|
||||
sbufReadU16Safe(&osdConfigMutable()->alt_alarm, src);
|
||||
sbufReadU16Safe(&osdConfigMutable()->dist_alarm, src);
|
||||
sbufReadU16Safe(&osdConfigMutable()->neg_alt_alarm, src);
|
||||
osdStartFullRedraw();
|
||||
}
|
||||
|
||||
break;
|
||||
case MSP2_INAV_OSD_SET_PREFERENCES:
|
||||
{
|
||||
sbufReadU8Safe(&osdConfigMutable()->video_system, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->main_voltage_decimals, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->ahi_reverse_roll, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->crosshairs_style, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->left_sidebar_scroll, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->right_sidebar_scroll, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->sidebar_scroll_arrows, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->units, src);
|
||||
sbufReadU8Safe(&osdConfigMutable()->stats_energy_unit, src);
|
||||
osdStartFullRedraw();
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "fc/fc_msp_box.h"
|
||||
#include "fc/runtime_config.h"
|
||||
|
||||
#include "io/osd.h"
|
||||
|
||||
#include "sensors/diagnostics.h"
|
||||
#include "sensors/sensors.h"
|
||||
|
||||
|
@ -72,6 +74,9 @@ static const box_t boxes[CHECKBOX_ITEM_COUNT + 1] = {
|
|||
{ BOXCAMERA1, "CAMERA CONTROL 1", 39 },
|
||||
{ BOXCAMERA2, "CAMERA CONTROL 2", 40 },
|
||||
{ BOXCAMERA3, "CAMERA CONTROL 3", 41 },
|
||||
{ BOXOSDALT1, "OSD ALT 1", 42 },
|
||||
{ BOXOSDALT2, "OSD ALT 2", 43 },
|
||||
{ BOXOSDALT3, "OSD ALT 3", 43 },
|
||||
{ CHECKBOX_ITEM_COUNT, NULL, 0xFF }
|
||||
};
|
||||
|
||||
|
@ -240,6 +245,18 @@ void initActiveBoxIds(void)
|
|||
activeBoxIds[activeBoxIdCount++] = BOXCAMERA2;
|
||||
activeBoxIds[activeBoxIdCount++] = BOXCAMERA3;
|
||||
#endif
|
||||
|
||||
#if defined(USE_OSD) && defined(OSD_LAYOUT_COUNT)
|
||||
#if OSD_LAYOUT_COUNT > 0
|
||||
activeBoxIds[activeBoxIdCount++] = BOXOSDALT1;
|
||||
#if OSD_LAYOUT_COUNT > 1
|
||||
activeBoxIds[activeBoxIdCount++] = BOXOSDALT2;
|
||||
#if OSD_LAYOUT_COUNT > 2
|
||||
activeBoxIds[activeBoxIdCount++] = BOXOSDALT3;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#define IS_ENABLED(mask) (mask == 0 ? 0 : 1)
|
||||
|
@ -289,6 +306,9 @@ void packBoxModeFlags(boxBitmask_t * mspBoxModeFlags)
|
|||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMERA1)), BOXCAMERA1);
|
||||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMERA2)), BOXCAMERA2);
|
||||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMERA3)), BOXCAMERA3);
|
||||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXOSDALT1)), BOXOSDALT1);
|
||||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXOSDALT2)), BOXOSDALT2);
|
||||
CHECK_ACTIVE_BOX(IS_ENABLED(IS_RC_MODE_ACTIVE(BOXOSDALT3)), BOXOSDALT3);
|
||||
|
||||
memset(mspBoxModeFlags, 0, sizeof(boxBitmask_t));
|
||||
for (uint32_t i = 0; i < activeBoxIdCount; i++) {
|
||||
|
|
|
@ -41,7 +41,15 @@ static bool isUsingNAVModes = false;
|
|||
#endif
|
||||
|
||||
boxBitmask_t rcModeActivationMask; // one bit per mode defined in boxId_e
|
||||
STATIC_ASSERT(CHECKBOX_ITEM_COUNT <= 32, too_many_box_modes);
|
||||
|
||||
// TODO(alberto): It looks like we can now safely remove this assert, since everything
|
||||
// but BB is able to handle more than 32 boxes and all the definitions use
|
||||
// CHECKBOX_ITEM_COUNT rather than hardcoded values. Note, however, that BB will only
|
||||
// log the first 32 flight modes, so the ones affecting actual flight should be <= 32.
|
||||
//
|
||||
// Leaving the assert commented for now, just in case there are some unexpected issues
|
||||
// and someone else has to debug it.
|
||||
// STATIC_ASSERT(CHECKBOX_ITEM_COUNT <= 32, too_many_box_modes);
|
||||
|
||||
PG_REGISTER_ARRAY(modeActivationCondition_t, MAX_MODE_ACTIVATION_CONDITION_COUNT, modeActivationConditions, PG_MODE_ACTIVATION_PROFILE, 0);
|
||||
PG_REGISTER(modeActivationOperatorConfig_t, modeActivationOperatorConfig, PG_MODE_ACTIVATION_OPERATOR_CONFIG, 0);
|
||||
|
|
|
@ -56,6 +56,9 @@ typedef enum {
|
|||
BOXCAMERA1 = 29,
|
||||
BOXCAMERA2 = 30,
|
||||
BOXCAMERA3 = 31,
|
||||
BOXOSDALT1 = 32,
|
||||
BOXOSDALT2 = 33,
|
||||
BOXOSDALT3 = 34,
|
||||
CHECKBOX_ITEM_COUNT
|
||||
} boxId_e;
|
||||
|
||||
|
|
|
@ -1454,158 +1454,10 @@ groups:
|
|||
- name: osd_sidebar_scroll_arrows
|
||||
field: sidebar_scroll_arrows
|
||||
type: bool
|
||||
|
||||
- name: osd_main_voltage_pos
|
||||
field: item_pos[OSD_MAIN_BATT_VOLTAGE]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_main_voltage_decimals
|
||||
field: main_voltage_decimals
|
||||
min: 1
|
||||
max: 2
|
||||
- name: osd_rssi_pos
|
||||
field: item_pos[OSD_RSSI_VALUE]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_flytimer_pos
|
||||
field: item_pos[OSD_FLYTIME]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_ontime_pos
|
||||
field: item_pos[OSD_ONTIME]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_flymode_pos
|
||||
field: item_pos[OSD_FLYMODE]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_throttle_pos
|
||||
field: item_pos[OSD_THROTTLE_POS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_vtx_channel_pos
|
||||
field: item_pos[OSD_VTX_CHANNEL]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_crosshairs_pos
|
||||
field: item_pos[OSD_CROSSHAIRS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_artificial_horizon_pos
|
||||
field: item_pos[OSD_ARTIFICIAL_HORIZON]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_horizon_sidebars_pos
|
||||
field: item_pos[OSD_HORIZON_SIDEBARS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_current_draw_pos
|
||||
field: item_pos[OSD_CURRENT_DRAW]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_mah_drawn_pos
|
||||
field: item_pos[OSD_MAH_DRAWN]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_wh_drawn_pos
|
||||
field: item_pos[OSD_WH_DRAWN]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_bat_remaining_capacity_pos
|
||||
field: item_pos[OSD_BATTERY_REMAINING_CAPACITY]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_bat_remaining_percent_pos
|
||||
field: item_pos[OSD_BATTERY_REMAINING_PERCENT]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_craft_name_pos
|
||||
field: item_pos[OSD_CRAFT_NAME]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_gps_speed_pos
|
||||
field: item_pos[OSD_GPS_SPEED]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_gps_sats_pos
|
||||
field: item_pos[OSD_GPS_SATS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_gps_lon_pos
|
||||
field: item_pos[OSD_GPS_LON]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_gps_lat_pos
|
||||
field: item_pos[OSD_GPS_LAT]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_home_dir_pos
|
||||
field: item_pos[OSD_HOME_DIR]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_home_dist_pos
|
||||
field: item_pos[OSD_HOME_DIST]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_altitude_pos
|
||||
field: item_pos[OSD_ALTITUDE]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_vario_pos
|
||||
field: item_pos[OSD_VARIO]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_vario_num_pos
|
||||
field: item_pos[OSD_VARIO_NUM]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_pid_roll_pos
|
||||
field: item_pos[OSD_ROLL_PIDS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_pid_pitch_pos
|
||||
field: item_pos[OSD_PITCH_PIDS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_pid_yaw_pos
|
||||
field: item_pos[OSD_YAW_PIDS]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_power_pos
|
||||
field: item_pos[OSD_POWER]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_air_speed_pos
|
||||
field: item_pos[OSD_AIR_SPEED]
|
||||
min: 0
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_ontime_flytime_pos
|
||||
field: item_pos[OSD_ONTIME_FLYTIME]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_rtc_time_pos
|
||||
field: item_pos[OSD_RTC_TIME]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_messages_pos
|
||||
field: item_pos[OSD_MESSAGES]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_gps_hdop_pos
|
||||
field: item_pos[OSD_GPS_HDOP]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_main_cell_voltage_pos
|
||||
field: item_pos[OSD_MAIN_BATT_CELL_VOLTAGE]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_throttle_auto_thr_pos
|
||||
field: item_pos[OSD_THROTTLE_POS_AUTO_THR]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_heading_graph_pos
|
||||
field: item_pos[OSD_HEADING_GRAPH]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_efficiency_mah_pos
|
||||
field: item_pos[OSD_EFFICIENCY_MAH_PER_KM]
|
||||
max: OSD_POS_MAX_CLI
|
||||
- name: osd_efficiency_wh_pos
|
||||
field: item_pos[OSD_EFFICIENCY_WH_PER_KM]
|
||||
max: OSD_POS_MAX_CLI
|
||||
|
||||
- name: PG_SYSTEM_CONFIG
|
||||
type: systemConfig_t
|
||||
|
|
|
@ -86,11 +86,6 @@
|
|||
#define VIDEO_BUFFER_CHARS_PAL 480
|
||||
#define IS_DISPLAY_PAL (displayScreenSize(osdDisplayPort) == VIDEO_BUFFER_CHARS_PAL)
|
||||
|
||||
// Character coordinate and attributes
|
||||
#define OSD_POS(x,y) (x | (y << 5))
|
||||
#define OSD_X(x) (x & 0x001F)
|
||||
#define OSD_Y(x) ((x >> 5) & 0x001F)
|
||||
|
||||
#define CENTIMETERS_TO_CENTIFEET(cm) (cm * (328 / 100.0))
|
||||
#define CENTIMETERS_TO_FEET(cm) (cm * (328 / 10000.0))
|
||||
#define CENTIMETERS_TO_METERS(cm) (cm / 100)
|
||||
|
@ -120,6 +115,8 @@
|
|||
})
|
||||
|
||||
static timeUs_t flyTime = 0;
|
||||
static unsigned currentLayout = 0;
|
||||
static int layoutOverride = -1;
|
||||
|
||||
typedef struct statistic_s {
|
||||
uint16_t max_speed;
|
||||
|
@ -161,7 +158,7 @@ static displayPort_t *osdDisplayPort;
|
|||
#define AH_SIDEBAR_WIDTH_POS 7
|
||||
#define AH_SIDEBAR_HEIGHT_POS 3
|
||||
|
||||
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 0);
|
||||
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 1);
|
||||
|
||||
static int digitCount(int32_t value)
|
||||
{
|
||||
|
@ -265,7 +262,7 @@ static int digitCount(int32_t value)
|
|||
*/
|
||||
static void osdFormatDistanceSymbol(char *buff, int32_t dist)
|
||||
{
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
if (osdFormatCentiNumber(buff + 1, CENTIMETERS_TO_CENTIFEET(dist), FEET_PER_MILE, 0, 3, 3)) {
|
||||
buff[0] = SYM_DIST_MI;
|
||||
|
@ -292,7 +289,7 @@ static void osdFormatDistanceSymbol(char *buff, int32_t dist)
|
|||
static void osdFormatDistanceStr(char *buff, int32_t dist)
|
||||
{
|
||||
int32_t centifeet;
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
centifeet = CENTIMETERS_TO_CENTIFEET(dist);
|
||||
if (abs(centifeet) < FEET_PER_MILE * 100 / 2) {
|
||||
|
@ -325,7 +322,7 @@ static void osdFormatDistanceSymbol(char *buff, int32_t dist)
|
|||
*/
|
||||
static int32_t osdConvertVelocityToUnit(int32_t vel)
|
||||
{
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_UK:
|
||||
FALLTHROUGH;
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
|
@ -343,7 +340,7 @@ static int32_t osdConvertVelocityToUnit(int32_t vel)
|
|||
*/
|
||||
static void osdFormatVelocityStr(char* buff, int32_t vel)
|
||||
{
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_UK:
|
||||
FALLTHROUGH;
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
|
@ -362,7 +359,7 @@ static void osdFormatVelocityStr(char* buff, int32_t vel)
|
|||
*/
|
||||
static void osdFormatAltitudeSymbol(char *buff, int32_t alt)
|
||||
{
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
if (osdFormatCentiNumber(buff + 1, CENTIMETERS_TO_CENTIFEET(alt), 1000, 0, 2, 3)) {
|
||||
// Scaled to kft
|
||||
|
@ -394,7 +391,7 @@ static void osdFormatAltitudeSymbol(char *buff, int32_t alt)
|
|||
static void osdFormatAltitudeStr(char *buff, int32_t alt)
|
||||
{
|
||||
int32_t value;
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
value = CENTIMETERS_TO_FEET(alt);
|
||||
tfp_sprintf(buff, "%d%c", value, SYM_FT);
|
||||
|
@ -818,12 +815,13 @@ static int16_t osdGetHeading(void)
|
|||
|
||||
static bool osdDrawSingleElement(uint8_t item)
|
||||
{
|
||||
if (!VISIBLE(osdConfig()->item_pos[item])) {
|
||||
uint16_t pos = osdConfig()->item_pos[currentLayout][item];
|
||||
if (!OSD_VISIBLE(pos)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
|
||||
uint8_t elemPosX = OSD_X(pos);
|
||||
uint8_t elemPosY = OSD_Y(pos);
|
||||
textAttributes_t elemAttr = TEXT_ATTRIBUTES_NONE;
|
||||
char buff[32];
|
||||
|
||||
|
@ -1082,7 +1080,7 @@ static bool osdDrawSingleElement(uint8_t item)
|
|||
|
||||
case OSD_CROSSHAIRS:
|
||||
osdCrosshairsBounds(&elemPosX, &elemPosY, NULL);
|
||||
switch (osdConfig()->crosshairs_style) {
|
||||
switch ((osd_crosshairs_style_e)osdConfig()->crosshairs_style) {
|
||||
case OSD_CROSSHAIRS_STYLE_DEFAULT:
|
||||
buff[0] = SYM_AH_CENTER_LINE;
|
||||
buff[1] = SYM_AH_CENTER;
|
||||
|
@ -1128,7 +1126,7 @@ static bool osdDrawSingleElement(uint8_t item)
|
|||
|
||||
// Convert pitchAngle to y compensation value
|
||||
pitchAngle = ((pitchAngle * 25) / AH_MAX_PITCH) - 41; // 41 = 4 * 9 + 5
|
||||
crosshairsVisible = VISIBLE(osdConfig()->item_pos[OSD_CROSSHAIRS]);
|
||||
crosshairsVisible = OSD_VISIBLE(osdConfig()->item_pos[currentLayout][OSD_CROSSHAIRS]);
|
||||
if (crosshairsVisible) {
|
||||
uint8_t cx, cy, cl;
|
||||
osdCrosshairsBounds(&cx, &cy, &cl);
|
||||
|
@ -1271,7 +1269,7 @@ static bool osdDrawSingleElement(uint8_t item)
|
|||
{
|
||||
int16_t value = getEstimatedActualVelocity(Z);
|
||||
char sym;
|
||||
switch (osdConfig()->units) {
|
||||
switch ((osd_unit_e)osdConfig()->units) {
|
||||
case OSD_UNIT_IMPERIAL:
|
||||
// Convert to centifeet/s
|
||||
value = CENTIMETERS_TO_CENTIFEET(value);
|
||||
|
@ -1603,67 +1601,75 @@ static uint8_t osdIncElementIndex(uint8_t elementIndex)
|
|||
void osdDrawNextElement(void)
|
||||
{
|
||||
static uint8_t elementIndex = 0;
|
||||
// Prevent infinite loop when no elements are enabled
|
||||
uint8_t index = elementIndex;
|
||||
do {
|
||||
elementIndex = osdIncElementIndex(elementIndex);
|
||||
} while(!osdDrawSingleElement(elementIndex));
|
||||
} while(!osdDrawSingleElement(elementIndex) && index != elementIndex);
|
||||
}
|
||||
|
||||
void pgResetFn_osdConfig(osdConfig_t *osdConfig)
|
||||
{
|
||||
osdConfig->item_pos[OSD_ALTITUDE] = OSD_POS(1, 0) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_MAIN_BATT_VOLTAGE] = OSD_POS(12, 0) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_RSSI_VALUE] = OSD_POS(23, 0) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_ALTITUDE] = OSD_POS(1, 0) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_MAIN_BATT_VOLTAGE] = OSD_POS(12, 0) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_RSSI_VALUE] = OSD_POS(23, 0) | OSD_VISIBLE_FLAG;
|
||||
//line 2
|
||||
osdConfig->item_pos[OSD_HOME_DIST] = OSD_POS(1, 1);
|
||||
osdConfig->item_pos[OSD_TRIP_DIST] = OSD_POS(1, 2);
|
||||
osdConfig->item_pos[OSD_MAIN_BATT_CELL_VOLTAGE] = OSD_POS(12, 1);
|
||||
osdConfig->item_pos[OSD_GPS_SPEED] = OSD_POS(23, 1);
|
||||
osdConfig->item_pos[0][OSD_HOME_DIST] = OSD_POS(1, 1);
|
||||
osdConfig->item_pos[0][OSD_TRIP_DIST] = OSD_POS(1, 2);
|
||||
osdConfig->item_pos[0][OSD_MAIN_BATT_CELL_VOLTAGE] = OSD_POS(12, 1);
|
||||
osdConfig->item_pos[0][OSD_GPS_SPEED] = OSD_POS(23, 1);
|
||||
|
||||
osdConfig->item_pos[OSD_THROTTLE_POS] = OSD_POS(1, 2) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_THROTTLE_POS_AUTO_THR] = OSD_POS(6, 2);
|
||||
osdConfig->item_pos[OSD_HEADING] = OSD_POS(12, 2);
|
||||
osdConfig->item_pos[OSD_HEADING_GRAPH] = OSD_POS(18, 2);
|
||||
osdConfig->item_pos[OSD_CURRENT_DRAW] = OSD_POS(1, 3) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_MAH_DRAWN] = OSD_POS(1, 4) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_WH_DRAWN] = OSD_POS(1, 5);
|
||||
osdConfig->item_pos[OSD_BATTERY_REMAINING_CAPACITY] = OSD_POS(1, 6);
|
||||
osdConfig->item_pos[OSD_BATTERY_REMAINING_PERCENT] = OSD_POS(1, 7);
|
||||
osdConfig->item_pos[0][OSD_THROTTLE_POS] = OSD_POS(1, 2) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_THROTTLE_POS_AUTO_THR] = OSD_POS(6, 2);
|
||||
osdConfig->item_pos[0][OSD_HEADING] = OSD_POS(12, 2);
|
||||
osdConfig->item_pos[0][OSD_HEADING_GRAPH] = OSD_POS(18, 2);
|
||||
osdConfig->item_pos[0][OSD_CURRENT_DRAW] = OSD_POS(1, 3) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_MAH_DRAWN] = OSD_POS(1, 4) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_WH_DRAWN] = OSD_POS(1, 5);
|
||||
osdConfig->item_pos[0][OSD_BATTERY_REMAINING_CAPACITY] = OSD_POS(1, 6);
|
||||
osdConfig->item_pos[0][OSD_BATTERY_REMAINING_PERCENT] = OSD_POS(1, 7);
|
||||
|
||||
osdConfig->item_pos[OSD_EFFICIENCY_MAH_PER_KM] = OSD_POS(1, 5);
|
||||
osdConfig->item_pos[OSD_EFFICIENCY_WH_PER_KM] = OSD_POS(1, 5);
|
||||
osdConfig->item_pos[0][OSD_EFFICIENCY_MAH_PER_KM] = OSD_POS(1, 5);
|
||||
osdConfig->item_pos[0][OSD_EFFICIENCY_WH_PER_KM] = OSD_POS(1, 5);
|
||||
|
||||
// avoid OSD_VARIO under OSD_CROSSHAIRS
|
||||
osdConfig->item_pos[OSD_VARIO] = OSD_POS(23, 5);
|
||||
osdConfig->item_pos[0][OSD_VARIO] = OSD_POS(23, 5);
|
||||
// OSD_VARIO_NUM at the right of OSD_VARIO
|
||||
osdConfig->item_pos[OSD_VARIO_NUM] = OSD_POS(24, 7);
|
||||
osdConfig->item_pos[OSD_HOME_DIR] = OSD_POS(14, 11);
|
||||
osdConfig->item_pos[OSD_ARTIFICIAL_HORIZON] = OSD_POS(8, 6) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_HORIZON_SIDEBARS] = OSD_POS(8, 6) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_VARIO_NUM] = OSD_POS(24, 7);
|
||||
osdConfig->item_pos[0][OSD_HOME_DIR] = OSD_POS(14, 11);
|
||||
osdConfig->item_pos[0][OSD_ARTIFICIAL_HORIZON] = OSD_POS(8, 6) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_HORIZON_SIDEBARS] = OSD_POS(8, 6) | OSD_VISIBLE_FLAG;
|
||||
|
||||
osdConfig->item_pos[OSD_CRAFT_NAME] = OSD_POS(20, 2);
|
||||
osdConfig->item_pos[OSD_VTX_CHANNEL] = OSD_POS(8, 6);
|
||||
osdConfig->item_pos[0][OSD_CRAFT_NAME] = OSD_POS(20, 2);
|
||||
osdConfig->item_pos[0][OSD_VTX_CHANNEL] = OSD_POS(8, 6);
|
||||
|
||||
osdConfig->item_pos[OSD_ONTIME] = OSD_POS(23, 8);
|
||||
osdConfig->item_pos[OSD_FLYTIME] = OSD_POS(23, 9);
|
||||
osdConfig->item_pos[OSD_ONTIME_FLYTIME] = OSD_POS(23, 11) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_RTC_TIME] = OSD_POS(23, 12);
|
||||
osdConfig->item_pos[0][OSD_ONTIME] = OSD_POS(23, 8);
|
||||
osdConfig->item_pos[0][OSD_FLYTIME] = OSD_POS(23, 9);
|
||||
osdConfig->item_pos[0][OSD_ONTIME_FLYTIME] = OSD_POS(23, 11) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_RTC_TIME] = OSD_POS(23, 12);
|
||||
|
||||
osdConfig->item_pos[OSD_GPS_SATS] = OSD_POS(0, 11) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_GPS_HDOP] = OSD_POS(0, 10);
|
||||
osdConfig->item_pos[0][OSD_GPS_SATS] = OSD_POS(0, 11) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_GPS_HDOP] = OSD_POS(0, 10);
|
||||
|
||||
osdConfig->item_pos[OSD_GPS_LAT] = OSD_POS(0, 12);
|
||||
osdConfig->item_pos[OSD_FLYMODE] = OSD_POS(12, 12) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[OSD_GPS_LON] = OSD_POS(18, 12);
|
||||
osdConfig->item_pos[0][OSD_GPS_LAT] = OSD_POS(0, 12);
|
||||
osdConfig->item_pos[0][OSD_FLYMODE] = OSD_POS(12, 12) | OSD_VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_GPS_LON] = OSD_POS(18, 12);
|
||||
|
||||
osdConfig->item_pos[OSD_ROLL_PIDS] = OSD_POS(2, 10);
|
||||
osdConfig->item_pos[OSD_PITCH_PIDS] = OSD_POS(2, 11);
|
||||
osdConfig->item_pos[OSD_YAW_PIDS] = OSD_POS(2, 12);
|
||||
osdConfig->item_pos[OSD_POWER] = OSD_POS(15, 1);
|
||||
osdConfig->item_pos[0][OSD_ROLL_PIDS] = OSD_POS(2, 10);
|
||||
osdConfig->item_pos[0][OSD_PITCH_PIDS] = OSD_POS(2, 11);
|
||||
osdConfig->item_pos[0][OSD_YAW_PIDS] = OSD_POS(2, 12);
|
||||
osdConfig->item_pos[0][OSD_POWER] = OSD_POS(15, 1);
|
||||
|
||||
osdConfig->item_pos[OSD_AIR_SPEED] = OSD_POS(3, 5);
|
||||
osdConfig->item_pos[0][OSD_AIR_SPEED] = OSD_POS(3, 5);
|
||||
|
||||
// Under OSD_FLYMODE. TODO: Might not be visible on NTSC?
|
||||
osdConfig->item_pos[OSD_MESSAGES] = OSD_POS(1, 13) | VISIBLE_FLAG;
|
||||
osdConfig->item_pos[0][OSD_MESSAGES] = OSD_POS(1, 13) | OSD_VISIBLE_FLAG;
|
||||
|
||||
for (unsigned ii = 1; ii < OSD_LAYOUT_COUNT; ii++) {
|
||||
for (unsigned jj = 0; jj < ARRAYLEN(osdConfig->item_pos[0]); jj++) {
|
||||
osdConfig->item_pos[ii][jj] = osdConfig->item_pos[0][jj] & ~OSD_VISIBLE_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
osdConfig->rssi_alarm = 20;
|
||||
osdConfig->time_alarm = 10;
|
||||
|
@ -2001,6 +2007,34 @@ void osdUpdate(timeUs_t currentTimeUs)
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(OSD_ALTERNATE_LAYOUT_COUNT) && OSD_ALTERNATE_LAYOUT_COUNT > 0
|
||||
// Check if the layout has changed. Higher numbered
|
||||
// boxes take priority.
|
||||
unsigned activeLayout;
|
||||
if (layoutOverride >= 0) {
|
||||
activeLayout = layoutOverride;
|
||||
} else {
|
||||
#if OSD_ALTERNATE_LAYOUT_COUNT > 2
|
||||
if (IS_RC_MODE_ACTIVE(BOXOSDALT3))
|
||||
activeLayout = 3;
|
||||
else
|
||||
#endif
|
||||
#if OSD_ALTERNATE_LAYOUT_COUNT > 1
|
||||
if (IS_RC_MODE_ACTIVE(BOXOSDALT2))
|
||||
activeLayout = 2;
|
||||
else
|
||||
#endif
|
||||
if (IS_RC_MODE_ACTIVE(BOXOSDALT1))
|
||||
activeLayout = 1;
|
||||
else
|
||||
activeLayout = 0;
|
||||
}
|
||||
if (currentLayout != activeLayout) {
|
||||
currentLayout = activeLayout;
|
||||
osdStartFullRedraw();
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DRAW_FREQ_DENOM 4
|
||||
#define STATS_FREQ_DENOM 50
|
||||
counter++;
|
||||
|
@ -2032,4 +2066,16 @@ void osdStartFullRedraw(void)
|
|||
fullRedraw = true;
|
||||
}
|
||||
|
||||
void osdOverrideLayout(int layout)
|
||||
{
|
||||
layoutOverride = constrain(layout, -1, ARRAYLEN(osdConfig()->item_pos) - 1);
|
||||
}
|
||||
|
||||
bool osdItemIsFixed(osd_items_e item)
|
||||
{
|
||||
return item == OSD_CROSSHAIRS ||
|
||||
item == OSD_ARTIFICIAL_HORIZON ||
|
||||
item == OSD_HORIZON_SIDEBARS;
|
||||
}
|
||||
|
||||
#endif // OSD
|
||||
|
|
|
@ -20,10 +20,18 @@
|
|||
#include "common/time.h"
|
||||
#include "config/parameter_group.h"
|
||||
|
||||
#define VISIBLE_FLAG 0x0800
|
||||
#define VISIBLE(x) (x & VISIBLE_FLAG)
|
||||
#define OSD_POS_MAX 0x3FF
|
||||
#define OSD_POS_MAX_CLI (OSD_POS_MAX | VISIBLE_FLAG)
|
||||
#ifndef OSD_ALTERNATE_LAYOUT_COUNT
|
||||
#define OSD_ALTERNATE_LAYOUT_COUNT 3
|
||||
#endif
|
||||
#define OSD_LAYOUT_COUNT (OSD_ALTERNATE_LAYOUT_COUNT + 1)
|
||||
|
||||
#define OSD_VISIBLE_FLAG 0x0800
|
||||
#define OSD_VISIBLE(x) ((x) & OSD_VISIBLE_FLAG)
|
||||
#define OSD_POS(x,y) ((x) | ((y) << 5))
|
||||
#define OSD_X(x) ((x) & 0x001F)
|
||||
#define OSD_Y(x) (((x) >> 5) & 0x001F)
|
||||
#define OSD_POS_MAX 0x3FF
|
||||
#define OSD_POS_MAX_CLI (OSD_POS_MAX | OSD_VISIBLE_FLAG)
|
||||
|
||||
typedef enum {
|
||||
OSD_RSSI_VALUE,
|
||||
|
@ -94,7 +102,8 @@ typedef enum {
|
|||
} osd_sidebar_scroll_e;
|
||||
|
||||
typedef struct osdConfig_s {
|
||||
uint16_t item_pos[OSD_ITEM_COUNT];
|
||||
// Layouts
|
||||
uint16_t item_pos[OSD_LAYOUT_COUNT][OSD_ITEM_COUNT];
|
||||
|
||||
// Alarms
|
||||
uint8_t rssi_alarm; // rssi %
|
||||
|
@ -109,13 +118,13 @@ typedef struct osdConfig_s {
|
|||
// Preferences
|
||||
uint8_t main_voltage_decimals;
|
||||
uint8_t ahi_reverse_roll;
|
||||
osd_crosshairs_style_e crosshairs_style;
|
||||
osd_sidebar_scroll_e left_sidebar_scroll;
|
||||
osd_sidebar_scroll_e right_sidebar_scroll;
|
||||
uint8_t crosshairs_style; // from osd_crosshairs_style_e
|
||||
uint8_t left_sidebar_scroll; // from osd_sidebar_scroll_e
|
||||
uint8_t right_sidebar_scroll; // from osd_sidebar_scroll_e
|
||||
uint8_t sidebar_scroll_arrows;
|
||||
|
||||
osd_unit_e units;
|
||||
osd_stats_energy_unit_e stats_energy_unit;
|
||||
uint8_t units; // from osd_unit_e
|
||||
uint8_t stats_energy_unit; // from osd_stats_energy_unit_e
|
||||
} osdConfig_t;
|
||||
|
||||
PG_DECLARE(osdConfig_t, osdConfig);
|
||||
|
@ -124,3 +133,7 @@ struct displayPort_s;
|
|||
void osdInit(struct displayPort_s *osdDisplayPort);
|
||||
void osdUpdate(timeUs_t currentTimeUs);
|
||||
void osdStartFullRedraw(void);
|
||||
// Sets a fixed OSD layout ignoring the RC input. Set it
|
||||
// to -1 to disable the override.
|
||||
void osdOverrideLayout(int layout);
|
||||
bool osdItemIsFixed(osd_items_e item);
|
||||
|
|
|
@ -31,3 +31,10 @@
|
|||
|
||||
#define MSP2_INAV_MIXER 0x2010
|
||||
#define MSP2_INAV_SET_MIXER 0x2011
|
||||
|
||||
#define MSP2_INAV_OSD_LAYOUTS 0x2012
|
||||
#define MSP2_INAV_OSD_SET_LAYOUT_ITEM 0x2013
|
||||
#define MSP2_INAV_OSD_ALARMS 0x2014
|
||||
#define MSP2_INAV_OSD_SET_ALARMS 0x2015
|
||||
#define MSP2_INAV_OSD_PREFERENCES 0x2016
|
||||
#define MSP2_INAV_OSD_SET_PREFERENCES 0x2017
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#define USE_DTERM_NOTCH
|
||||
#define USE_ACC_NOTCH
|
||||
#define USE_CMS
|
||||
#define CMS_MENU_OSD
|
||||
#define USE_DASHBOARD
|
||||
#define USE_OLED_UG2864
|
||||
#define USE_MSP_DISPLAYPORT
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue