Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stick overlays to OSD #7167

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/main/interface/settings.c
Expand Up @@ -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]) },
#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
// 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)},
Expand Down
110 changes: 102 additions & 8 deletions src/main/io/osd.c
Expand Up @@ -103,6 +103,11 @@
#define VIDEO_BUFFER_CHARS_PAL 480
#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[] = {
"ON TIME ",
"TOTAL ARM",
Expand Down Expand Up @@ -143,8 +148,29 @@ typedef struct statistic_s {
uint8_t min_link_quality;
} 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] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be made conditional, or the build will fail with a warning for targets without USE_OSD_PROFILES. (Protip: Having a look at the result of the CI checks will reveal this type of problem.)

Copy link
Contributor Author

@pkruger pkruger Dec 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, yes I should probably use the CI checks and reap the benefits. Now passing...

{ 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;
#define REFRESH_1S 1000 * 1000

Expand Down Expand Up @@ -227,7 +253,7 @@ static const uint8_t osdElementDisplayOrder[] = {
#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
Expand Down Expand Up @@ -505,15 +531,10 @@ void changeOsdProfileIndex(uint8_t profileIndex)

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)) {
return false;
}
#endif

uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
char buff[OSD_ELEMENT_BUFFER_LENGTH] = "";
Expand Down Expand Up @@ -1184,6 +1205,58 @@ static bool osdDrawSingleElement(uint8_t item)
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scaleRange can invert direction, just map to OSD_STICK_OVERLAY_HEIGHT, 0

Also this equation is IMO incorrect, it works only when PWM_RANGE_MAX = 2*PWM_RANGE_MIN

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scalerange: uint8_t y_pos = (uint8_t)scaleRange(constrain(rcData[vertical_channel], PWM_RANGE_MIN, PWM_RANGE_MAX), PWM_RANGE_MIN, PWM_RANGE_MAX, OSD_STICK_OVERLAY_HEIGHT, 0) + OSD_STICK_OVERLAY_HEIGHT - 1;
Doesn't work, not sure why.

Why do you think it only works with PWM_RANGE_MAX = 2*PWM_RANGE_MIN?


ledvinap marked this conversation as resolved.
Show resolved Hide resolved
osdDrawStickOverlayPos(osd_item, x_pos, y_pos);
}
#endif

static void osdDrawElements(void)
{
displayClearScreen(osdDisplayPort);
Expand Down Expand Up @@ -1236,6 +1309,18 @@ static void osdDrawElements(void)
osdDrawSingleElement(OSD_LOG_STATUS);
}
#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)
Expand Down Expand Up @@ -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_2] = OSD_TIMER(OSD_TIMER_SRC_TOTAL_ARMED, OSD_TIMER_PREC_SECOND, 10);

osdConfig->overlay_radio_mode = 2;

osdConfig->rssi_alarm = 20;
osdConfig->cap_alarm = 2200;
osdConfig->alt_alarm = 100; // meters or feet depend on configuration
Expand Down Expand Up @@ -1872,4 +1959,11 @@ void osdSuppressStats(bool 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
15 changes: 13 additions & 2 deletions src/main/io/osd.h
Expand Up @@ -33,10 +33,13 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
#define OSD_PROFILE_BITS_POS 11
#define OSD_PROFILE_1_FLAG (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_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
Expand All @@ -46,6 +49,10 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
#define OSD_X(x) (x & 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
// Stored as 15[alarm:8][precision:4][source:4]0
#define OSD_TIMER(src, prec, alarm) ((src & 0x0F) | ((prec & 0x0F) << 4) | ((alarm & 0xFF ) << 8))
Expand Down Expand Up @@ -107,6 +114,8 @@ typedef enum {
OSD_FLIP_ARROW,
OSD_LINK_QUALITY,
OSD_FLIGHT_DIST,
OSD_STICK_OVERLAY_LEFT,
OSD_STICK_OVERLAY_RIGHT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to increment the version of the osdConfig parameter group here, as we are increasing OSD_ITEM_COUNT. See https://github.com/betaflight/betaflight/blob/master/docs/development/ParameterGroups.md

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. Thanks, now fixed.

OSD_ITEM_COUNT // MUST BE LAST
} osd_items_e;

Expand Down Expand Up @@ -213,6 +222,7 @@ typedef struct osdConfig_s {
uint8_t core_temp_alarm;
uint8_t ahInvert; // invert the artificial horizon
uint8_t osdProfileIndex;
uint8_t overlay_radio_mode;
} osdConfig_t;

PG_DECLARE(osdConfig_t, osdConfig);
Expand All @@ -233,3 +243,4 @@ void osdSuppressStats(bool flag);
void setOsdProfile(uint8_t value);
uint8_t getCurrentOsdProfileIndex(void);
void changeOsdProfileIndex(uint8_t profileIndex);
bool osdElementVisible(uint16_t value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anywhere externally (or meant to be), so this shouldn't be here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used in cms.c, i.e. in osd.h VISIBLE(x) is defined as: #define VISIBLE(x) osdElementVisible(x).

1 change: 1 addition & 0 deletions src/main/target/common_post.h
Expand Up @@ -127,6 +127,7 @@
#if !defined(USE_OSD)
#undef USE_RX_LINK_QUALITY_INFO
#undef USE_OSD_PROFILES
#undef USE_OSD_STICK_OVERLAY
#endif

/* If either VTX_CONTROL or VTX_COMMON is undefined then remove common code and device drivers */
Expand Down
1 change: 1 addition & 0 deletions src/main/target/common_pre.h
Expand Up @@ -235,4 +235,5 @@
#define USE_RX_LINK_QUALITY_INFO
#define USE_ESC_SENSOR_TELEMETRY
#define USE_OSD_PROFILES
#define USE_OSD_STICK_OVERLAY
#endif