From e8165fd262cb31e4eea0409ccf787d3e6015eaf2 Mon Sep 17 00:00:00 2001 From: Mr D - RC Date: Thu, 27 Feb 2025 08:37:47 +0000 Subject: [PATCH 1/2] Add throttle gauge option to OSD Allow pilots to see the throttle as a digital gauge. Similar appearance to the VSI vario gauge. --- src/main/io/osd.c | 8 +++++++ src/main/io/osd.h | 1 + src/main/io/osd_canvas.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/main/io/osd_canvas.h | 1 + src/main/io/osd_common.c | 17 +++++++++++++++ src/main/io/osd_common.h | 3 +++ src/main/io/osd_grid.c | 32 +++++++++++++++++++++++++++ src/main/io/osd_grid.h | 1 + 8 files changed, 110 insertions(+) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index d44ea0a8988..de2d02ab0b7 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2852,6 +2852,13 @@ static bool osdDrawSingleElement(uint8_t item) return true; } + case OSD_THROTTLE_GAUGE: + { + bool useScaled = navigationIsControllingThrottle(); + osdThrottleGauge(osdDisplayPort, osdGetDisplayPortCanvas(), OSD_DRAW_POINT_GRID(elemPosX, elemPosY), getThrottlePercent(useScaled)); + return true; + } + #if defined(USE_BARO) || defined(USE_GPS) case OSD_VARIO: { @@ -4246,6 +4253,7 @@ void pgResetFn_osdLayoutsConfig(osdLayoutsConfig_t *osdLayoutsConfig) osdLayoutsConfig->item_pos[0][OSD_ATTITUDE_ROLL] = OSD_POS(1, 7); osdLayoutsConfig->item_pos[0][OSD_ATTITUDE_PITCH] = OSD_POS(1, 8); + osdLayoutsConfig->item_pos[0][OSD_THROTTLE_GAUGE] = OSD_POS(23, 5); // avoid OSD_VARIO under OSD_CROSSHAIRS osdLayoutsConfig->item_pos[0][OSD_VARIO] = OSD_POS(23, 5); // OSD_VARIO_NUM at the right of OSD_VARIO diff --git a/src/main/io/osd.h b/src/main/io/osd.h index b2e94b52729..1451c775e71 100644 --- a/src/main/io/osd.h +++ b/src/main/io/osd.h @@ -313,6 +313,7 @@ typedef enum { OSD_H_DIST_TO_FENCE, OSD_V_DIST_TO_FENCE, OSD_NAV_FW_ALT_CONTROL_RESPONSE, + OSD_THROTTLE_GAUGE, OSD_ITEM_COUNT // MUST BE LAST } osd_items_e; diff --git a/src/main/io/osd_canvas.c b/src/main/io/osd_canvas.c index 47dd4ee47bc..14e787216a5 100644 --- a/src/main/io/osd_canvas.c +++ b/src/main/io/osd_canvas.c @@ -71,6 +71,53 @@ static void osdCanvasVarioRect(int *y, int *h, displayCanvas_t *canvas, int midY *h = height; } +void osdCanvasDrawThrottleGauge(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, uint8_t thrPos) +{ + UNUSED(display); + + static uint8_t prevThr = 0; + + if (ABS(prevThr - thrPos) < 10) { + return; + } + + // Make sure we clear the grid buffer + uint8_t gx; + uint8_t gy; + osdDrawPointGetGrid(&gx, &gy, display, canvas, p); + osdGridBufferClearGridRect(gx, gy, 1, OSD_THROTTLE_GAUGE_HEIGHT_ROWS); + + int x = gx * canvas->gridElementWidth; + int w = canvas->gridElementWidth; + int y = gy * canvas->gridElementHeight; + int h = OSD_THROTTLE_GAUGE_HEIGHT_ROWS * canvas->gridElementHeight; + + displayCanvasClearRect(canvas, x, y, w, h); + + if (thrPos >= 100) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else if (thrPos >= 90) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 80) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else if (thrPos >= 70) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 60) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else if (thrPos >= 50) + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 40) + displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else if (thrPos >= 30) + displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 20) + displayCanvasDrawCharacter(canvas, x, y, SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else if (thrPos >= 10) + displayCanvasDrawCharacter(canvas, x, y, SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + + prevThr = thrPos; +} + void osdCanvasDrawVario(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float zvel) { UNUSED(display); diff --git a/src/main/io/osd_canvas.h b/src/main/io/osd_canvas.h index 6a8d013e807..0e01d1ab162 100644 --- a/src/main/io/osd_canvas.h +++ b/src/main/io/osd_canvas.h @@ -32,6 +32,7 @@ typedef struct displayPort_s displayPort_t; typedef struct displayCanvas_s displayCanvas_t; typedef struct osdDrawPoint_s osdDrawPoint_t; +void osdCanvasDrawThrottleGauge(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, uint8_t thrPos); void osdCanvasDrawVario(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float zvel); void osdCanvasDrawDirArrow(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float degrees); void osdCanvasDrawArtificialHorizon(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float pitchAngle, float rollAngle); diff --git a/src/main/io/osd_common.c b/src/main/io/osd_common.c index 6969e181a5d..729ac58b572 100644 --- a/src/main/io/osd_common.c +++ b/src/main/io/osd_common.c @@ -109,6 +109,23 @@ void osdDrawPointGetPixels(int *px, int *py, const displayPort_t *display, const } } +void osdThrottleGauge(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, uint8_t thrPos) +{ + uint8_t gx; + uint8_t gy; + + #if defined(USE_CANVAS) + if (canvas) { + osdCanvasDrawThrottleGauge(display, canvas, p, thrPos); + } else { +#endif + osdDrawPointGetGrid(&gx, &gy, display, canvas, p); + osdGridDrawThrottleGauge(display, gx, gy, thrPos); +#if defined(USE_CANVAS) + } +#endif +} + void osdDrawVario(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float zvel) { uint8_t gx; diff --git a/src/main/io/osd_common.h b/src/main/io/osd_common.h index 0f700c445e4..a032747effc 100644 --- a/src/main/io/osd_common.h +++ b/src/main/io/osd_common.h @@ -52,6 +52,8 @@ int16_t osdGetSpeedFromSelectedSource(void); #define OSD_VARIO_CM_S_PER_ARROW 50 // 1 arrow = 50cm/s #define OSD_VARIO_HEIGHT_ROWS 5 +#define OSD_THROTTLE_GAUGE_HEIGHT_ROWS 5 + #define OSD_AHI_HEIGHT 9 #define OSD_AHI_WIDTH 11 #define OSD_AHI_PREV_SIZE (OSD_AHI_WIDTH > OSD_AHI_HEIGHT ? OSD_AHI_WIDTH : OSD_AHI_HEIGHT) @@ -92,6 +94,7 @@ typedef struct osdDrawPoint_s { void osdDrawPointGetGrid(uint8_t *gx, uint8_t *gy, const displayPort_t *display, const displayCanvas_t *canvas, const osdDrawPoint_t *p); void osdDrawPointGetPixels(int *px, int *py, const displayPort_t *display, const displayCanvas_t *canvas, const osdDrawPoint_t *p); +void osdThrottleGauge(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, uint8_t thrPos); void osdDrawVario(displayPort_t *display, displayCanvas_t *canvas, const osdDrawPoint_t *p, float zvel); // Draws an arrow at the given point, where 0 degrees points to the top of the viewport and // positive angles result in clockwise rotation. If eraseBefore is true, the rect surrouing diff --git a/src/main/io/osd_grid.c b/src/main/io/osd_grid.c index 9e79194498d..658db9e2df0 100644 --- a/src/main/io/osd_grid.c +++ b/src/main/io/osd_grid.c @@ -56,6 +56,38 @@ typedef struct osd_sidebar_s { uint8_t idle; } osd_sidebar_t; +void osdGridDrawThrottleGauge(displayPort_t *display, unsigned gx, unsigned gy, uint8_t thrPos) +{ + uint16_t thrChars[] = {SYM_BLANK, SYM_BLANK, SYM_BLANK, SYM_BLANK, SYM_BLANK}; + + if (thrPos >= 100) + thrChars[4] = SYM_VARIO_UP_2A; + else if (thrPos >= 90) + thrChars[4] = SYM_VARIO_UP_1A; + if (thrPos >= 80) + thrChars[3] = SYM_VARIO_UP_2A; + else if (thrPos >= 70) + thrChars[3] = SYM_VARIO_UP_1A; + if (thrPos >= 60) + thrChars[2] = SYM_VARIO_UP_2A; + else if (thrPos >= 50) + thrChars[2] = SYM_VARIO_UP_1A; + if (thrPos >= 40) + thrChars[1] = SYM_VARIO_UP_2A; + else if (thrPos >= 30) + thrChars[1] = SYM_VARIO_UP_1A; + if (thrPos >= 20) + thrChars[0] = SYM_VARIO_UP_2A; + else if (thrPos >= 10) + thrChars[0] = SYM_VARIO_UP_1A; + + displayWriteChar(display, gx, gy, thrChars[0]); + displayWriteChar(display, gx, gy + 1, thrChars[1]); + displayWriteChar(display, gx, gy + 2, thrChars[2]); + displayWriteChar(display, gx, gy + 3, thrChars[3]); + displayWriteChar(display, gx, gy + 4, thrChars[4]); +} + void osdGridDrawVario(displayPort_t *display, unsigned gx, unsigned gy, float zvel) { int v = zvel / OSD_VARIO_CM_S_PER_ARROW; diff --git a/src/main/io/osd_grid.h b/src/main/io/osd_grid.h index baf69dc9186..c4f0eaa9ee2 100644 --- a/src/main/io/osd_grid.h +++ b/src/main/io/osd_grid.h @@ -28,6 +28,7 @@ typedef struct displayPort_s displayPort_t; +void osdGridDrawThrottleGauge(displayPort_t *display, unsigned gx, unsigned gy, uint8_t thrPos); void osdGridDrawVario(displayPort_t *display, unsigned gx, unsigned gy, float zvel); void osdGridDrawDirArrow(displayPort_t *display, unsigned gx, unsigned gy, float degrees); void osdGridDrawArtificialHorizon(displayPort_t *display, unsigned gx, unsigned gy, float pitchAngle, float rollAngle); From 619b2e2282b5148f36362230f8db56fd57738925 Mon Sep 17 00:00:00 2001 From: Mr D - RC Date: Fri, 7 Mar 2025 07:31:04 +0000 Subject: [PATCH 2/2] Added new symbols --- src/main/drivers/osd_symbols.h | 4 ++++ src/main/io/osd_canvas.c | 34 ++++++++++++++++++++++++---------- src/main/io/osd_grid.c | 22 +++++++++++----------- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/drivers/osd_symbols.h b/src/main/drivers/osd_symbols.h index 35b9c61a424..2a457f385c5 100644 --- a/src/main/drivers/osd_symbols.h +++ b/src/main/drivers/osd_symbols.h @@ -237,6 +237,10 @@ #define SYM_RX_BAND 0x169 // 361 RX Band #define SYM_RX_MODE 0x16A // 362 RX Mode +#define SYM_THR_GAUGE_EMPTY 0x16B // 363 Throttle gauge empty +#define SYM_THR_GAUGE_HALF 0x16C // 364 Throttle gauge 1 step +#define SYM_THR_GAUGE_FULL 0x16D // 365 Throttle gauge 2 steps + #define SYM_AH_CH_TYPE3 0x190 // 400 to 402, crosshair 3 #define SYM_AH_CH_TYPE4 0x193 // 403 to 405, crosshair 4 #define SYM_AH_CH_TYPE5 0x196 // 406 to 408, crosshair 5 diff --git a/src/main/io/osd_canvas.c b/src/main/io/osd_canvas.c index 14e787216a5..1fbe8771774 100644 --- a/src/main/io/osd_canvas.c +++ b/src/main/io/osd_canvas.c @@ -95,25 +95,39 @@ void osdCanvasDrawThrottleGauge(displayPort_t *display, displayCanvas_t *canvas, displayCanvasClearRect(canvas, x, y, w, h); if (thrPos >= 100) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_THR_GAUGE_FULL, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); else if (thrPos >= 90) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_THR_GAUGE_HALF, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 4), SYM_THR_GAUGE_EMPTY, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 80) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_THR_GAUGE_FULL, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); else if (thrPos >= 70) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_THR_GAUGE_HALF, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 3), SYM_THR_GAUGE_EMPTY, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 60) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_THR_GAUGE_FULL, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); else if (thrPos >= 50) - displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_THR_GAUGE_HALF, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else + displayCanvasDrawCharacter(canvas, x, y + (canvas->gridElementHeight * 2), SYM_THR_GAUGE_EMPTY, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 40) - displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_THR_GAUGE_FULL, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); else if (thrPos >= 30) - displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_THR_GAUGE_HALF, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else + displayCanvasDrawCharacter(canvas, x, y + canvas->gridElementHeight, SYM_THR_GAUGE_EMPTY, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + if (thrPos >= 20) - displayCanvasDrawCharacter(canvas, x, y, SYM_VARIO_UP_2A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y, SYM_THR_GAUGE_FULL, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); else if (thrPos >= 10) - displayCanvasDrawCharacter(canvas, x, y, SYM_VARIO_UP_1A, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + displayCanvasDrawCharacter(canvas, x, y, SYM_THR_GAUGE_HALF, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); + else + displayCanvasDrawCharacter(canvas, x, y, SYM_THR_GAUGE_EMPTY, DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT); prevThr = thrPos; } diff --git a/src/main/io/osd_grid.c b/src/main/io/osd_grid.c index 658db9e2df0..fae92d195b7 100644 --- a/src/main/io/osd_grid.c +++ b/src/main/io/osd_grid.c @@ -58,28 +58,28 @@ typedef struct osd_sidebar_s { void osdGridDrawThrottleGauge(displayPort_t *display, unsigned gx, unsigned gy, uint8_t thrPos) { - uint16_t thrChars[] = {SYM_BLANK, SYM_BLANK, SYM_BLANK, SYM_BLANK, SYM_BLANK}; + uint16_t thrChars[] = {SYM_THR_GAUGE_EMPTY, SYM_THR_GAUGE_EMPTY, SYM_THR_GAUGE_EMPTY, SYM_THR_GAUGE_EMPTY, SYM_THR_GAUGE_EMPTY}; if (thrPos >= 100) - thrChars[4] = SYM_VARIO_UP_2A; + thrChars[0] = SYM_THR_GAUGE_FULL; else if (thrPos >= 90) - thrChars[4] = SYM_VARIO_UP_1A; + thrChars[0] = SYM_THR_GAUGE_HALF; if (thrPos >= 80) - thrChars[3] = SYM_VARIO_UP_2A; + thrChars[1] = SYM_THR_GAUGE_FULL; else if (thrPos >= 70) - thrChars[3] = SYM_VARIO_UP_1A; + thrChars[1] = SYM_THR_GAUGE_HALF; if (thrPos >= 60) - thrChars[2] = SYM_VARIO_UP_2A; + thrChars[2] = SYM_THR_GAUGE_FULL; else if (thrPos >= 50) - thrChars[2] = SYM_VARIO_UP_1A; + thrChars[2] = SYM_THR_GAUGE_HALF; if (thrPos >= 40) - thrChars[1] = SYM_VARIO_UP_2A; + thrChars[3] = SYM_THR_GAUGE_FULL; else if (thrPos >= 30) - thrChars[1] = SYM_VARIO_UP_1A; + thrChars[3] = SYM_THR_GAUGE_HALF; if (thrPos >= 20) - thrChars[0] = SYM_VARIO_UP_2A; + thrChars[4] = SYM_THR_GAUGE_FULL; else if (thrPos >= 10) - thrChars[0] = SYM_VARIO_UP_1A; + thrChars[4] = SYM_THR_GAUGE_HALF; displayWriteChar(display, gx, gy, thrChars[0]); displayWriteChar(display, gx, gy + 1, thrChars[1]);