mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-21 23:35:34 +03:00
Add OSD Stick Overlay feature - fix issue 3988
This commit is contained in:
parent
586eef94e5
commit
ef459cb161
5 changed files with 124 additions and 10 deletions
|
@ -1088,6 +1088,13 @@ const clivalue_t valueTable[] = {
|
||||||
{ "osd_log_status_pos", VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, OSD_POSCFG_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, item_pos[OSD_LOG_STATUS]) },
|
{ "osd_log_status_pos", VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, OSD_POSCFG_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, item_pos[OSD_LOG_STATUS]) },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
|
{ "osd_stick_overlay_left_pos", VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, OSD_POSCFG_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, item_pos[OSD_STICK_OVERLAY_LEFT]) },
|
||||||
|
{ "osd_stick_overlay_right_pos", VAR_UINT16 | MASTER_VALUE, .config.minmax = { 0, OSD_POSCFG_MAX }, PG_OSD_CONFIG, offsetof(osdConfig_t, item_pos[OSD_STICK_OVERLAY_RIGHT]) },
|
||||||
|
|
||||||
|
{ "osd_stick_overlay_radio_mode", VAR_UINT8 | MASTER_VALUE, .config.minmax = { 1, 4 }, PG_OSD_CONFIG, offsetof(osdConfig_t, overlay_radio_mode) },
|
||||||
|
#endif
|
||||||
|
|
||||||
// OSD stats enabled flags are stored as bitmapped values inside a 32bit parameter
|
// OSD stats enabled flags are stored as bitmapped values inside a 32bit parameter
|
||||||
// It is recommended to keep the settings order the same as the enumeration. This way the settings are displayed in the cli in the same order making it easier on the users
|
// It is recommended to keep the settings order the same as the enumeration. This way the settings are displayed in the cli in the same order making it easier on the users
|
||||||
{ "osd_stat_rtc_date_time", VAR_UINT32 | MASTER_VALUE | MODE_BITSET, .config.bitpos = OSD_STAT_RTC_DATE_TIME, PG_OSD_CONFIG, offsetof(osdConfig_t, enabled_stats)},
|
{ "osd_stat_rtc_date_time", VAR_UINT32 | MASTER_VALUE | MODE_BITSET, .config.bitpos = OSD_STAT_RTC_DATE_TIME, PG_OSD_CONFIG, offsetof(osdConfig_t, enabled_stats)},
|
||||||
|
|
|
@ -103,6 +103,11 @@
|
||||||
#define VIDEO_BUFFER_CHARS_PAL 480
|
#define VIDEO_BUFFER_CHARS_PAL 480
|
||||||
#define FULL_CIRCLE 360
|
#define FULL_CIRCLE 360
|
||||||
|
|
||||||
|
#define STICK_OVERLAY_HORIZONTAL_CHAR '-'
|
||||||
|
#define STICK_OVERLAY_VERTICAL_CHAR '|'
|
||||||
|
#define STICK_OVERLAY_CROSS_CHAR '+'
|
||||||
|
#define STICK_OVERLAY_CURSOR_CHAR '0'
|
||||||
|
|
||||||
const char * const osdTimerSourceNames[] = {
|
const char * const osdTimerSourceNames[] = {
|
||||||
"ON TIME ",
|
"ON TIME ",
|
||||||
"TOTAL ARM",
|
"TOTAL ARM",
|
||||||
|
@ -143,8 +148,29 @@ typedef struct statistic_s {
|
||||||
uint8_t min_link_quality;
|
uint8_t min_link_quality;
|
||||||
} statistic_t;
|
} statistic_t;
|
||||||
|
|
||||||
static statistic_t stats;
|
typedef struct radioControls_s {
|
||||||
|
uint8_t left_vertical;
|
||||||
|
uint8_t left_horizontal;
|
||||||
|
uint8_t right_vertical;
|
||||||
|
uint8_t right_horizontal;
|
||||||
|
} radioControls_t;
|
||||||
|
|
||||||
|
typedef enum radioModes_e {
|
||||||
|
MODE1,
|
||||||
|
MODE2,
|
||||||
|
MODE3,
|
||||||
|
MODE4
|
||||||
|
} radioModes_t;
|
||||||
|
|
||||||
|
static statistic_t stats;
|
||||||
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
|
static const radioControls_t radioModes[4] = {
|
||||||
|
{ PITCH, YAW, THROTTLE, ROLL }, // Mode 1
|
||||||
|
{ THROTTLE, YAW, PITCH, ROLL }, // Mode 2
|
||||||
|
{ PITCH, ROLL, THROTTLE, YAW }, // Mode 3
|
||||||
|
{ THROTTLE, ROLL, PITCH, YAW }, // Mode 4
|
||||||
|
};
|
||||||
|
#endif
|
||||||
timeUs_t resumeRefreshAt = 0;
|
timeUs_t resumeRefreshAt = 0;
|
||||||
#define REFRESH_1S 1000 * 1000
|
#define REFRESH_1S 1000 * 1000
|
||||||
|
|
||||||
|
@ -227,7 +253,7 @@ static const uint8_t osdElementDisplayOrder[] = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 3);
|
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the correct altitude symbol for the current unit system
|
* Gets the correct altitude symbol for the current unit system
|
||||||
|
@ -505,15 +531,10 @@ void changeOsdProfileIndex(uint8_t profileIndex)
|
||||||
|
|
||||||
static bool osdDrawSingleElement(uint8_t item)
|
static bool osdDrawSingleElement(uint8_t item)
|
||||||
{
|
{
|
||||||
#ifdef USE_OSD_PROFILES
|
|
||||||
if ((OSD_ELEMENT_PROFILE(osdConfig()->item_pos[item]) & osdProfile) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (!VISIBLE(osdConfig()->item_pos[item]) || BLINK(item)) {
|
if (!VISIBLE(osdConfig()->item_pos[item]) || BLINK(item)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||||
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
|
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
|
||||||
char buff[OSD_ELEMENT_BUFFER_LENGTH] = "";
|
char buff[OSD_ELEMENT_BUFFER_LENGTH] = "";
|
||||||
|
@ -1184,6 +1205,58 @@ static bool osdDrawSingleElement(uint8_t item)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
|
static void osdDrawStickOverlayAxis(uint8_t xpos, uint8_t ypos)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (unsigned x = 0; x < OSD_STICK_OVERLAY_WIDTH; x++) {
|
||||||
|
for (unsigned y = 0; y < OSD_STICK_OVERLAY_HEIGHT; y++) {
|
||||||
|
// draw the axes, vertical and horizonal
|
||||||
|
if ((x == ((OSD_STICK_OVERLAY_WIDTH - 1) / 2)) && (y == (OSD_STICK_OVERLAY_HEIGHT - 1) / 2)) {
|
||||||
|
displayWriteChar(osdDisplayPort, xpos + x, ypos + y, STICK_OVERLAY_CROSS_CHAR);
|
||||||
|
} else if (x == ((OSD_STICK_OVERLAY_WIDTH - 1) / 2)) {
|
||||||
|
displayWriteChar(osdDisplayPort, xpos + x, ypos + y, STICK_OVERLAY_VERTICAL_CHAR);
|
||||||
|
} else if (y == ((OSD_STICK_OVERLAY_HEIGHT - 1) / 2)) {
|
||||||
|
displayWriteChar(osdDisplayPort, xpos + x, ypos + y, STICK_OVERLAY_HORIZONTAL_CHAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osdDrawStickOverlayAxisItem(osd_items_e osd_item)
|
||||||
|
{
|
||||||
|
osdDrawStickOverlayAxis(OSD_X(osdConfig()->item_pos[osd_item]),
|
||||||
|
OSD_Y(osdConfig()->item_pos[osd_item]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osdDrawStickOverlayPos(osd_items_e osd_item, uint8_t xpos, uint8_t ypos)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[osd_item]);
|
||||||
|
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[osd_item]);
|
||||||
|
|
||||||
|
displayWriteChar(osdDisplayPort, elemPosX + xpos, elemPosY + ypos, STICK_OVERLAY_CURSOR_CHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osdDrawStickOverlayCursor(osd_items_e osd_item)
|
||||||
|
{
|
||||||
|
rc_alias_e vertical_channel, horizontal_channel;
|
||||||
|
|
||||||
|
if (osd_item == OSD_STICK_OVERLAY_LEFT) {
|
||||||
|
vertical_channel = radioModes[osdConfig()->overlay_radio_mode-1].left_vertical;
|
||||||
|
horizontal_channel = radioModes[osdConfig()->overlay_radio_mode-1].left_horizontal;
|
||||||
|
} else {
|
||||||
|
vertical_channel = radioModes[osdConfig()->overlay_radio_mode-1].right_vertical;
|
||||||
|
horizontal_channel = radioModes[osdConfig()->overlay_radio_mode-1].right_horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t x_pos = (uint8_t)scaleRange(constrain(rcData[horizontal_channel], PWM_RANGE_MIN, PWM_RANGE_MAX), PWM_RANGE_MIN, PWM_RANGE_MAX, 0, OSD_STICK_OVERLAY_WIDTH);
|
||||||
|
uint8_t y_pos = (uint8_t)scaleRange(PWM_RANGE_MAX - constrain(rcData[vertical_channel], PWM_RANGE_MIN, PWM_RANGE_MAX), PWM_RANGE_MIN, PWM_RANGE_MAX, 0, OSD_STICK_OVERLAY_HEIGHT) + OSD_STICK_OVERLAY_HEIGHT - 1;
|
||||||
|
|
||||||
|
osdDrawStickOverlayPos(osd_item, x_pos, y_pos);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void osdDrawElements(void)
|
static void osdDrawElements(void)
|
||||||
{
|
{
|
||||||
displayClearScreen(osdDisplayPort);
|
displayClearScreen(osdDisplayPort);
|
||||||
|
@ -1236,6 +1309,18 @@ static void osdDrawElements(void)
|
||||||
osdDrawSingleElement(OSD_LOG_STATUS);
|
osdDrawSingleElement(OSD_LOG_STATUS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
|
if (VISIBLE(osdConfig()->item_pos[OSD_STICK_OVERLAY_LEFT])) {
|
||||||
|
osdDrawStickOverlayAxisItem(OSD_STICK_OVERLAY_LEFT);
|
||||||
|
osdDrawStickOverlayCursor(OSD_STICK_OVERLAY_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VISIBLE(osdConfig()->item_pos[OSD_STICK_OVERLAY_RIGHT])) {
|
||||||
|
osdDrawStickOverlayAxisItem(OSD_STICK_OVERLAY_RIGHT);
|
||||||
|
osdDrawStickOverlayCursor(OSD_STICK_OVERLAY_RIGHT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgResetFn_osdConfig(osdConfig_t *osdConfig)
|
void pgResetFn_osdConfig(osdConfig_t *osdConfig)
|
||||||
|
@ -1274,6 +1359,8 @@ void pgResetFn_osdConfig(osdConfig_t *osdConfig)
|
||||||
osdConfig->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_ON, OSD_TIMER_PREC_SECOND, 10);
|
osdConfig->timers[OSD_TIMER_1] = OSD_TIMER(OSD_TIMER_SRC_ON, OSD_TIMER_PREC_SECOND, 10);
|
||||||
osdConfig->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_SECOND, 10);
|
osdConfig->timers[OSD_TIMER_2] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_SECOND, 10);
|
||||||
|
|
||||||
|
osdConfig->overlay_radio_mode = 2;
|
||||||
|
|
||||||
osdConfig->rssi_alarm = 20;
|
osdConfig->rssi_alarm = 20;
|
||||||
osdConfig->cap_alarm = 2200;
|
osdConfig->cap_alarm = 2200;
|
||||||
osdConfig->alt_alarm = 100; // meters or feet depend on configuration
|
osdConfig->alt_alarm = 100; // meters or feet depend on configuration
|
||||||
|
@ -1872,4 +1959,11 @@ void osdSuppressStats(bool flag)
|
||||||
{
|
{
|
||||||
suppressStatsDisplay = flag;
|
suppressStatsDisplay = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OSD_PROFILES
|
||||||
|
bool osdElementVisible(uint16_t value)
|
||||||
|
{
|
||||||
|
return (bool)((((value & OSD_PROFILE_MASK) >> OSD_PROFILE_BITS_POS) & osdProfile) != 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif // USE_OSD
|
#endif // USE_OSD
|
||||||
|
|
|
@ -33,10 +33,13 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
|
||||||
#define OSD_PROFILE_BITS_POS 11
|
#define OSD_PROFILE_BITS_POS 11
|
||||||
#define OSD_PROFILE_1_FLAG (1 << OSD_PROFILE_BITS_POS)
|
#define OSD_PROFILE_1_FLAG (1 << OSD_PROFILE_BITS_POS)
|
||||||
#define OSD_PROFILE_MASK (((1 << OSD_PROFILE_COUNT) - 1) << OSD_PROFILE_BITS_POS)
|
#define OSD_PROFILE_MASK (((1 << OSD_PROFILE_COUNT) - 1) << OSD_PROFILE_BITS_POS)
|
||||||
#define VISIBLE(x) ((x) & OSD_PROFILE_MASK)
|
|
||||||
#define OSD_POS_MAX 0x3FF
|
#define OSD_POS_MAX 0x3FF
|
||||||
#define OSD_POSCFG_MAX (OSD_PROFILE_MASK | 0x3FF) // For CLI values
|
#define OSD_POSCFG_MAX (OSD_PROFILE_MASK | 0x3FF) // For CLI values
|
||||||
#define OSD_ELEMENT_PROFILE(x) (((x) & OSD_PROFILE_MASK) >> OSD_PROFILE_BITS_POS)
|
#ifdef USE_OSD_PROFILES
|
||||||
|
#define VISIBLE(x) osdElementVisible(x)
|
||||||
|
#else
|
||||||
|
#define VISIBLE(x) ((x) & OSD_PROFILE_MASK)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Character coordinate
|
// Character coordinate
|
||||||
|
@ -46,6 +49,10 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
|
||||||
#define OSD_X(x) (x & OSD_POSITION_XY_MASK)
|
#define OSD_X(x) (x & OSD_POSITION_XY_MASK)
|
||||||
#define OSD_Y(x) ((x >> OSD_POSITION_BITS) & OSD_POSITION_XY_MASK)
|
#define OSD_Y(x) ((x >> OSD_POSITION_BITS) & OSD_POSITION_XY_MASK)
|
||||||
|
|
||||||
|
// Stick overlay size
|
||||||
|
#define OSD_STICK_OVERLAY_WIDTH 7
|
||||||
|
#define OSD_STICK_OVERLAY_HEIGHT 7
|
||||||
|
|
||||||
// Timer configuration
|
// Timer configuration
|
||||||
// Stored as 15[alarm:8][precision:4][source:4]0
|
// Stored as 15[alarm:8][precision:4][source:4]0
|
||||||
#define OSD_TIMER(src, prec, alarm) ((src & 0x0F) | ((prec & 0x0F) << 4) | ((alarm & 0xFF ) << 8))
|
#define OSD_TIMER(src, prec, alarm) ((src & 0x0F) | ((prec & 0x0F) << 4) | ((alarm & 0xFF ) << 8))
|
||||||
|
@ -107,6 +114,8 @@ typedef enum {
|
||||||
OSD_FLIP_ARROW,
|
OSD_FLIP_ARROW,
|
||||||
OSD_LINK_QUALITY,
|
OSD_LINK_QUALITY,
|
||||||
OSD_FLIGHT_DIST,
|
OSD_FLIGHT_DIST,
|
||||||
|
OSD_STICK_OVERLAY_LEFT,
|
||||||
|
OSD_STICK_OVERLAY_RIGHT,
|
||||||
OSD_ITEM_COUNT // MUST BE LAST
|
OSD_ITEM_COUNT // MUST BE LAST
|
||||||
} osd_items_e;
|
} osd_items_e;
|
||||||
|
|
||||||
|
@ -213,6 +222,7 @@ typedef struct osdConfig_s {
|
||||||
uint8_t core_temp_alarm;
|
uint8_t core_temp_alarm;
|
||||||
uint8_t ahInvert; // invert the artificial horizon
|
uint8_t ahInvert; // invert the artificial horizon
|
||||||
uint8_t osdProfileIndex;
|
uint8_t osdProfileIndex;
|
||||||
|
uint8_t overlay_radio_mode;
|
||||||
} osdConfig_t;
|
} osdConfig_t;
|
||||||
|
|
||||||
PG_DECLARE(osdConfig_t, osdConfig);
|
PG_DECLARE(osdConfig_t, osdConfig);
|
||||||
|
@ -233,3 +243,4 @@ void osdSuppressStats(bool flag);
|
||||||
void setOsdProfile(uint8_t value);
|
void setOsdProfile(uint8_t value);
|
||||||
uint8_t getCurrentOsdProfileIndex(void);
|
uint8_t getCurrentOsdProfileIndex(void);
|
||||||
void changeOsdProfileIndex(uint8_t profileIndex);
|
void changeOsdProfileIndex(uint8_t profileIndex);
|
||||||
|
bool osdElementVisible(uint16_t value);
|
||||||
|
|
|
@ -127,6 +127,7 @@
|
||||||
#if !defined(USE_OSD)
|
#if !defined(USE_OSD)
|
||||||
#undef USE_RX_LINK_QUALITY_INFO
|
#undef USE_RX_LINK_QUALITY_INFO
|
||||||
#undef USE_OSD_PROFILES
|
#undef USE_OSD_PROFILES
|
||||||
|
#undef USE_OSD_STICK_OVERLAY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If either VTX_CONTROL or VTX_COMMON is undefined then remove common code and device drivers */
|
/* If either VTX_CONTROL or VTX_COMMON is undefined then remove common code and device drivers */
|
||||||
|
|
|
@ -235,4 +235,5 @@
|
||||||
#define USE_RX_LINK_QUALITY_INFO
|
#define USE_RX_LINK_QUALITY_INFO
|
||||||
#define USE_ESC_SENSOR_TELEMETRY
|
#define USE_ESC_SENSOR_TELEMETRY
|
||||||
#define USE_OSD_PROFILES
|
#define USE_OSD_PROFILES
|
||||||
|
#define USE_OSD_STICK_OVERLAY
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue