From 1fd82cb334db6683474a551a3e9e4bfcae74f5df Mon Sep 17 00:00:00 2001 From: p-i-engineer Date: Sat, 30 May 2026 06:38:58 -0700 Subject: [PATCH 01/25] dshot ignore fix --- src/main/io/beeper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/io/beeper.c b/src/main/io/beeper.c index af0f826c88c..c8cc7769921 100644 --- a/src/main/io/beeper.c +++ b/src/main/io/beeper.c @@ -345,7 +345,9 @@ void beeperUpdate(timeUs_t currentTimeUs) if (!beeperIsOn) { #ifdef USE_DSHOT if (isMotorProtocolDshot() && !areMotorsRunning() && beeperConfig()->dshot_beeper_enabled - && currentTimeUs - lastDshotBeeperCommandTimeUs > getDShotBeaconGuardDelayUs()) + && currentTimeUs - lastDshotBeeperCommandTimeUs > getDShotBeaconGuardDelayUs() + && currentBeeperEntry->sequence[beeperPos] != 0 // added beeper timeout so dshot does not beep on "off" + && !(getBeeperOffMask() & (1 << (currentBeeperEntry->mode - 1)))) // added beeper ignore to dshot beacon { lastDshotBeeperCommandTimeUs = currentTimeUs; sendDShotCommand(beeperConfig()->dshot_beeper_tone); From 9dfbb9290a13d9ccc3da54e5e5cb3eb7a1c1e7a2 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:07:18 +0200 Subject: [PATCH 02/25] feat: lay out basic structure for new glide slope calculation --- src/main/io/osd.c | 48 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 55bca838f34..42ed3ab4ec4 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -191,6 +191,15 @@ typedef struct statistic_s { int32_t flightStartMWh; } statistic_t; +typedef struct glidePositionSample_s { + uint32_t distance_cm; // Total travel distance + int32_t altitude_cm; // Altitude +} glidePositionSample_t; + +static uint8_t glideSampleRate = 2; // 2Hz +static uint8_t glideSampleTimeFrame = 10; // seconds +static uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid + static statistic_t stats; static timeUs_t resumeRefreshAt = 0; @@ -2065,14 +2074,37 @@ static bool osdDrawSingleElement(uint8_t item) case OSD_GLIDESLOPE: { - float horizontalSpeed = gpsSol.groundSpeed; - float sinkRate = -getEstimatedActualVelocity(Z); - static pt1Filter_t gsFilterState; - const timeMs_t currentTimeMs = millis(); - static timeMs_t gsUpdatedTimeMs; - float glideSlope = horizontalSpeed / sinkRate; - glideSlope = pt1FilterApply4(&gsFilterState, isnormal(glideSlope) ? glideSlope : 200, 0.5, MS2S(currentTimeMs - gsUpdatedTimeMs)); - gsUpdatedTimeMs = currentTimeMs; + // float horizontalSpeed = gpsSol.groundSpeed; + // float sinkRate = -getEstimatedActualVelocity(Z); + // static pt1Filter_t gsFilterState; + // const timeMs_t currentTimeMs = millis(); + // static timeMs_t gsUpdatedTimeMs; + // float glideSlope = horizontalSpeed / sinkRate; + // glideSlope = pt1FilterApply4(&gsFilterState, isnormal(glideSlope) ? glideSlope : 200, 0.5, MS2S(currentTimeMs - gsUpdatedTimeMs)); + // gsUpdatedTimeMs = currentTimeMs; + + static uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; + static glidePositionSample_t glideBuffer[bufferSize] = 0; + static uint16_t glideBufferIndex = 0; + static timeMs_t glideLastSampleTime = 0; + static uint8_t samplesSinceLastClear = 0; + const timeMs_t currentTime = millis(); + + static float glideSlope = 0.0f; + + if (currentTime - glideLastSampleTime >= glideSampleRate) { + // Record a new sample + glideLastSampleTime = currentTime; + glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); + glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); + glideBufferIndex = (glideBufferIndex + 1) % bufferSize; + (samplesSinceLastClear < bufferSize) ? samplesSinceLastClear++ : 0; + + if (samplesSinceLastClear >= minimumSampleCount) { + // Calculate glide slope using the samples + + } + } buff[0] = SYM_GLIDESLOPE; if (glideSlope > 0.0f && glideSlope < 100.0f) { From c88af3c963f101952c9b404b1a29408149234def Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:27:07 +0200 Subject: [PATCH 03/25] fix: change glideBuffer allocation to static for now --- src/main/io/osd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 42ed3ab4ec4..66a25a6eaf5 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2084,9 +2084,8 @@ static bool osdDrawSingleElement(uint8_t item) // gsUpdatedTimeMs = currentTimeMs; static uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; - static glidePositionSample_t glideBuffer[bufferSize] = 0; - static uint16_t glideBufferIndex = 0; - static timeMs_t glideLastSampleTime = 0; + static glidePositionSample_t glideBuffer[20]; // Need to add semi-dynamic allocation based on glideSampleRate and glideSampleTimeFrame later to allow for changing this in settings + static uint8_t glideBufferIndex = 0; static uint8_t samplesSinceLastClear = 0; const timeMs_t currentTime = millis(); From 8cdc279ce0215437a45d187ad86a587936120e09 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:28:06 +0200 Subject: [PATCH 04/25] fix: incorrect comparison in sample interval calculation --- src/main/io/osd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 66a25a6eaf5..2a9fc4e7bd9 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2088,10 +2088,11 @@ static bool osdDrawSingleElement(uint8_t item) static uint8_t glideBufferIndex = 0; static uint8_t samplesSinceLastClear = 0; const timeMs_t currentTime = millis(); + const uint16_t sampleIntervalMs = 1000 / glideSampleRate; static float glideSlope = 0.0f; - if (currentTime - glideLastSampleTime >= glideSampleRate) { + if (currentTime - glideLastSampleTime >= sampleIntervalMs) { // Record a new sample glideLastSampleTime = currentTime; glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); From 586949badfdb180a42de81dd1f7dc4a9c7a08b77 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:28:28 +0200 Subject: [PATCH 05/25] fix: incorrect use of ternary in sample interval increment logic --- src/main/io/osd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 2a9fc4e7bd9..978229a0ad3 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2098,7 +2098,9 @@ static bool osdDrawSingleElement(uint8_t item) glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); glideBufferIndex = (glideBufferIndex + 1) % bufferSize; - (samplesSinceLastClear < bufferSize) ? samplesSinceLastClear++ : 0; + if (samplesSinceLastClear < bufferSize) { + samplesSinceLastClear++; + } if (samplesSinceLastClear >= minimumSampleCount) { // Calculate glide slope using the samples From 482975b0582643ef83bcec3c26bfa2c17411533d Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:28:57 +0200 Subject: [PATCH 06/25] refactor: rename glideSlope to glideRatio for clarity in OSD element refactor: update comments to reflect changes in glide ratio calculation --- src/main/io/osd.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 978229a0ad3..2bf52c34d08 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2074,15 +2074,9 @@ static bool osdDrawSingleElement(uint8_t item) case OSD_GLIDESLOPE: { - // float horizontalSpeed = gpsSol.groundSpeed; - // float sinkRate = -getEstimatedActualVelocity(Z); - // static pt1Filter_t gsFilterState; - // const timeMs_t currentTimeMs = millis(); - // static timeMs_t gsUpdatedTimeMs; - // float glideSlope = horizontalSpeed / sinkRate; - // glideSlope = pt1FilterApply4(&gsFilterState, isnormal(glideSlope) ? glideSlope : 200, 0.5, MS2S(currentTimeMs - gsUpdatedTimeMs)); - // gsUpdatedTimeMs = currentTimeMs; - + // Note: the element was originally named "Glide Slope" but actually shows the glide ratio + // The original naming is conserved in places to retain compatibility + static uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; static glidePositionSample_t glideBuffer[20]; // Need to add semi-dynamic allocation based on glideSampleRate and glideSampleTimeFrame later to allow for changing this in settings static uint8_t glideBufferIndex = 0; @@ -2090,7 +2084,7 @@ static bool osdDrawSingleElement(uint8_t item) const timeMs_t currentTime = millis(); const uint16_t sampleIntervalMs = 1000 / glideSampleRate; - static float glideSlope = 0.0f; + static float glideRatio = 0.0f; if (currentTime - glideLastSampleTime >= sampleIntervalMs) { // Record a new sample @@ -2103,14 +2097,14 @@ static bool osdDrawSingleElement(uint8_t item) } if (samplesSinceLastClear >= minimumSampleCount) { - // Calculate glide slope using the samples - + // Calculate glide ratio using the samples + glideRatio = calculateGlideRatioFromBuffer(glideBuffer, bufferSize); } } buff[0] = SYM_GLIDESLOPE; - if (glideSlope > 0.0f && glideSlope < 100.0f) { - osdFormatCentiNumber(buff + 1, glideSlope * 100.0f, 0, 2, 0, 3, false); + if (glideRatio > 0.0f && glideRatio < 100.0f) { + osdFormatCentiNumber(buff + 1, glideRatio * 100.0f, 0, 2, 0, 3, false); } else { buff[1] = buff[2] = buff[3] = '-'; } From 40cb69bb75f6a6c2228a761b2748276a4192ceff Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:44:22 +0200 Subject: [PATCH 07/25] fix: change glideSampleRate, glideSampleTimeFrame, and minimumSampleCount to const --- src/main/io/osd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 2bf52c34d08..0c455cb2bd4 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -196,9 +196,9 @@ typedef struct glidePositionSample_s { int32_t altitude_cm; // Altitude } glidePositionSample_t; -static uint8_t glideSampleRate = 2; // 2Hz -static uint8_t glideSampleTimeFrame = 10; // seconds -static uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid +static const uint8_t glideSampleRate = 2; // 2Hz +static const uint8_t glideSampleTimeFrame = 10; // seconds +static const uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid static statistic_t stats; @@ -2077,7 +2077,7 @@ static bool osdDrawSingleElement(uint8_t item) // Note: the element was originally named "Glide Slope" but actually shows the glide ratio // The original naming is conserved in places to retain compatibility - static uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; + const uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; static glidePositionSample_t glideBuffer[20]; // Need to add semi-dynamic allocation based on glideSampleRate and glideSampleTimeFrame later to allow for changing this in settings static uint8_t glideBufferIndex = 0; static uint8_t samplesSinceLastClear = 0; From affdb0c50b377b25721c37a7ddd11049015a6985 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:44:29 +0200 Subject: [PATCH 08/25] fix: add glideLastSampleTime to track the last sample time in osdDrawSingleElement --- src/main/io/osd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 0c455cb2bd4..fcbf926593b 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2081,6 +2081,7 @@ static bool osdDrawSingleElement(uint8_t item) static glidePositionSample_t glideBuffer[20]; // Need to add semi-dynamic allocation based on glideSampleRate and glideSampleTimeFrame later to allow for changing this in settings static uint8_t glideBufferIndex = 0; static uint8_t samplesSinceLastClear = 0; + static timeMs_t glideLastSampleTime = 0; const timeMs_t currentTime = millis(); const uint16_t sampleIntervalMs = 1000 / glideSampleRate; From 274691f68a40a860eaf8af7dd47ed7d94f561670 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:44:35 +0200 Subject: [PATCH 09/25] feat: add calculateGlideRatioFromBuffer function for glide ratio calculation from position samples --- src/main/io/osd.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index fcbf926593b..4f593d6555f 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1837,6 +1837,59 @@ static bool osdElementEnabled(uint8_t elementID, bool onlyCurrentLayout) { return elementEnabled; } + +// Linear regression: calculate glide ratio from position samples +// Returns glide ratio (horizontal distance per 1 unit vertical descent) +// Returns 0 if insufficient data or invalid conditions +static float calculateGlideRatioFromBuffer(const glidePositionSample_t *buffer, uint8_t sampleCount) +{ + // Least-squares linear regression: y = mx + b + // where x = horizontal distance, y = altitude + // We need: sumX, sumY, sumX², sumXY, and n (sample count) + + float sumX = 0.0f; // sum of distances + float sumY = 0.0f; // sum of altitudes + float sumXY = 0.0f; // sum of (distance * altitude) + float sumX2 = 0.0f; // sum of (distance²) + + for (uint8_t i = 0; i < sampleCount; i++) { + float x = (float)buffer[i].distance_cm; + float y = (float)buffer[i].altitude_cm; + + sumX += x; + sumY += y; + sumXY += x * y; + sumX2 += x * x; + } + + // Slope formula: m = (n·Σxy - Σx·Σy) / (n·Σx² - (Σx)²) + float n = (float)sampleCount; + float numerator = n * sumXY - sumX * sumY; + float denominator = n * sumX2 - sumX * sumX; + + // Avoid division by zero or degenerate cases + if (fabsf(denominator) < 1e-6f) { + return 0.0f; // Not enough variation in distance + } + + float slope = numerator / denominator; // altitude_change / distance_change + + // For descent, slope should be negative + if (slope >= 0.0f) { + return 0.0f; // Not descending + } + + // Glide ratio = distance / |altitude_change| = 1 / |slope| + float glideRatio = -1.0f / slope; + + // Sanity check: reasonable glide ratios are 1-100 + if (glideRatio > 0.1f && glideRatio < 100.0f) { + return glideRatio; + } + + return 0.0f; // Out of reasonable range +} + static bool osdDrawSingleElement(uint8_t item) { uint16_t pos = osdLayoutsConfig()->item_pos[currentLayout][item]; @@ -6501,6 +6554,7 @@ void osdEraseCustomItem(uint8_t item){ } + #endif // OSD unsigned getCurrentLayout(void){ From 47063ab7fd121d11abdd230050eaa82e96b54eb0 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:19:05 +0200 Subject: [PATCH 10/25] feat: implement lazy allocation for glide buffer to allow changing parameters via cli variables --- src/main/io/osd.c | 68 ++++++++++++++++++++++++++++++++++++++++------- src/main/io/osd.h | 2 ++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 4f593d6555f..d476f32ff85 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -191,6 +191,8 @@ typedef struct statistic_s { int32_t flightStartMWh; } statistic_t; +#define MAX_GLIDE_BUFFER_SIZE 240 // Maximum samples: 4 Hz * 60 seconds + typedef struct glidePositionSample_s { uint32_t distance_cm; // Total travel distance int32_t altitude_cm; // Altitude @@ -200,6 +202,11 @@ static const uint8_t glideSampleRate = 2; // 2Hz static const uint8_t glideSampleTimeFrame = 10; // seconds static const uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid +// Lazy-allocated glide buffer +static glidePositionSample_t *glideBuffer = NULL; +static uint16_t glideBufferAllocatedSize = 0; +static uint16_t glideBufferCurrentSize = 0; + static statistic_t stats; static timeUs_t resumeRefreshAt = 0; @@ -1837,6 +1844,36 @@ static bool osdElementEnabled(uint8_t elementID, bool onlyCurrentLayout) { return elementEnabled; } +// Manage lazy allocation and reallocation of glide buffer +// Returns the current buffer size, or 0 if allocation failed +static uint16_t ensureGlideBufferAllocated(uint16_t requiredSize) +{ + // Clamp to maximum size + if (requiredSize > MAX_GLIDE_BUFFER_SIZE) { + requiredSize = MAX_GLIDE_BUFFER_SIZE; + } + + // If already allocated with correct size, return it + if (glideBuffer != NULL && glideBufferAllocatedSize == requiredSize) { + return requiredSize; + } + + // Need to allocate or reallocate + glidePositionSample_t *newBuffer = (glidePositionSample_t *)realloc(glideBuffer, requiredSize * sizeof(glidePositionSample_t)); + + if (newBuffer == NULL) { + return 0; // Allocation failed, keep old buffer + } + + glideBuffer = newBuffer; + glideBufferAllocatedSize = requiredSize; + + // Reset sample tracking when buffer changes size + glideBufferCurrentSize = 0; + + return requiredSize; +} + // Linear regression: calculate glide ratio from position samples // Returns glide ratio (horizontal distance per 1 unit vertical descent) @@ -2130,14 +2167,23 @@ static bool osdDrawSingleElement(uint8_t item) // Note: the element was originally named "Glide Slope" but actually shows the glide ratio // The original naming is conserved in places to retain compatibility - const uint8_t bufferSize = glideSampleRate * glideSampleTimeFrame; - static glidePositionSample_t glideBuffer[20]; // Need to add semi-dynamic allocation based on glideSampleRate and glideSampleTimeFrame later to allow for changing this in settings + uint8_t sampleRate = osdConfig()->glide_sample_rate; + uint8_t timeFrame = osdConfig()->glide_sample_time_frame; + const uint16_t requiredBufferSize = sampleRate * timeFrame; + uint16_t bufferSize = ensureGlideBufferAllocated(requiredBufferSize); + + if (bufferSize == 0) { + // Allocation failed, display error + buff[0] = SYM_GLIDESLOPE; + buff[1] = buff[2] = buff[3] = '-'; + buff[4] = '\0'; + break; + } + static uint8_t glideBufferIndex = 0; - static uint8_t samplesSinceLastClear = 0; static timeMs_t glideLastSampleTime = 0; const timeMs_t currentTime = millis(); - const uint16_t sampleIntervalMs = 1000 / glideSampleRate; - + const uint16_t sampleIntervalMs = 1000 / sampleRate; static float glideRatio = 0.0f; if (currentTime - glideLastSampleTime >= sampleIntervalMs) { @@ -2146,13 +2192,13 @@ static bool osdDrawSingleElement(uint8_t item) glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); glideBufferIndex = (glideBufferIndex + 1) % bufferSize; - if (samplesSinceLastClear < bufferSize) { - samplesSinceLastClear++; + if (glideBufferCurrentSize < bufferSize) { + glideBufferCurrentSize++; } - if (samplesSinceLastClear >= minimumSampleCount) { + if (glideBufferCurrentSize >= minimumSampleCount) { // Calculate glide ratio using the samples - glideRatio = calculateGlideRatioFromBuffer(glideBuffer, bufferSize); + glideRatio = calculateGlideRatioFromBuffer(glideBuffer, glideBufferCurrentSize); } } @@ -4494,7 +4540,9 @@ PG_RESET_TEMPLATE(osdConfig_t, osdConfig, .stats_page_auto_swap_time = SETTING_OSD_STATS_PAGE_AUTO_SWAP_TIME_DEFAULT, .stats_show_metric_efficiency = SETTING_OSD_STATS_SHOW_METRIC_EFFICIENCY_DEFAULT, - .radar_peers_display_time = SETTING_OSD_RADAR_PEERS_DISPLAY_TIME_DEFAULT + .radar_peers_display_time = SETTING_OSD_RADAR_PEERS_DISPLAY_TIME_DEFAULT, + .glide_sample_rate = SETTING_OSD_GLIDE_SAMPLE_RATE_DEFAULT, + .glide_sample_time_frame = SETTING_OSD_GLIDE_SAMPLE_TIME_FRAME_DEFAULT ); void pgResetFn_osdLayoutsConfig(osdLayoutsConfig_t *osdLayoutsConfig) diff --git a/src/main/io/osd.h b/src/main/io/osd.h index 88240ff84c0..5d60375977c 100644 --- a/src/main/io/osd.h +++ b/src/main/io/osd.h @@ -540,6 +540,8 @@ typedef struct osdConfig_s { uint8_t geozoneDistanceWarning; // Distance to fence or action bool geozoneDistanceType; // Shows a countdown timer or distance to fence/action #endif + uint8_t glide_sample_rate; // Glide slope sampling rate in Hz (default 2) + uint8_t glide_sample_time_frame; // Glide slope sampling time frame in seconds (default 10) } osdConfig_t; PG_DECLARE(osdConfig_t, osdConfig); From 06886e7ac7459bf0e03480405b89859d168148ea Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:21:03 +0200 Subject: [PATCH 11/25] feat: add osd_glide_sample_rate and osd_glide_sample_time_frame settings for glide slope configuration --- docs/Settings.md | 20 ++++++++++++++++++++ src/main/fc/settings.yaml | 14 ++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/docs/Settings.md b/docs/Settings.md index 39e3de90d52..6294c957fa6 100644 --- a/docs/Settings.md +++ b/docs/Settings.md @@ -4872,6 +4872,26 @@ Value under which the OSD axis g force indicators will blink (g) --- +### osd_glide_sample_rate + +Glide slope sampling rate in Hz (1-4 Hz). Higher rates give more responsive glide slope calculations but use more CPU. + +| Default | Min | Max | +| --- | --- | --- | +| 2 | 1 | 4 | + +--- + +### osd_glide_sample_time_frame + +Glide slope sampling time frame in seconds (5-60 seconds). Longer frames provide more stable glide slope estimates. + +| Default | Min | Max | +| --- | --- | --- | +| 10 | 5 | 60 | + +--- + ### osd_highlight_djis_missing_font_symbols Show question marks where there is no symbol in the DJI font to represent the INAV OSD element's symbol. When off, blank spaces will be used. Only relevent for DJICOMPAT modes. diff --git a/src/main/fc/settings.yaml b/src/main/fc/settings.yaml index 6ef471e3bb0..bd37e16ac13 100644 --- a/src/main/fc/settings.yaml +++ b/src/main/fc/settings.yaml @@ -3909,6 +3909,20 @@ groups: field: osd_switch_indicators_align_left type: bool default_value: ON + - name: osd_glide_sample_rate + description: "Glide slope sampling rate in Hz (1-4 Hz). Higher rates give more responsive glide slope calculations but use more CPU." + field: glide_sample_rate + type: uint8_t + min: 1 + max: 4 + default_value: 2 + - name: osd_glide_sample_time_frame + description: "Glide slope sampling time frame in seconds (5-60 seconds). Longer frames provide more stable glide slope estimates." + field: glide_sample_time_frame + type: uint8_t + min: 5 + max: 60 + default_value: 10 - name: PG_OSD_COMMON_CONFIG type: osdCommonConfig_t From 059bb962e51b1efffd232ff7371243f375a16b7e Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:38:11 +0200 Subject: [PATCH 12/25] feat: add isDataValidForGlideRatio function to validate glide ratio conditions fix: reset glide buffer when glide ratio conditions are not met --- src/main/io/osd.c | 54 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index d476f32ff85..1b259053b75 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1874,6 +1874,23 @@ static uint16_t ensureGlideBufferAllocated(uint16_t requiredSize) return requiredSize; } +static bool isDataValidForGlideRatio() { + // Check if we have been ascending for more than 5 seconds, which would indicate that the glide ratio is not valid + static timeMs_t lastDescentTime = 0; + if (getEstimatedActualVelocity(Z) < 0) { // Descending + lastDescentTime = millis(); + } else if (millis() - lastDescentTime > 5000) { // Ascending for more than 5 seconds + return false; + } + + // Check if the throttle is above a certain threshold, which would indicate that we are under power and the glide ratio is not valid + if (getThrottlePercent(true) > 10) { + return false; + } + + return true; +} + // Linear regression: calculate glide ratio from position samples // Returns glide ratio (horizontal distance per 1 unit vertical descent) @@ -2182,23 +2199,40 @@ static bool osdDrawSingleElement(uint8_t item) static uint8_t glideBufferIndex = 0; static timeMs_t glideLastSampleTime = 0; + static uint8_t samplesSinceLastClear = 0; const timeMs_t currentTime = millis(); const uint16_t sampleIntervalMs = 1000 / sampleRate; static float glideRatio = 0.0f; - + if (currentTime - glideLastSampleTime >= sampleIntervalMs) { // Record a new sample - glideLastSampleTime = currentTime; - glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); - glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); - glideBufferIndex = (glideBufferIndex + 1) % bufferSize; - if (glideBufferCurrentSize < bufferSize) { - glideBufferCurrentSize++; + + if (!isDataValidForGlideRatio()) { + // Conditions not valid for glide ratio, reset buffer + for (uint16_t i = 0; i < bufferSize; i++) { + glideBuffer[i].distance_cm = 0; + glideBuffer[i].altitude_cm = 0; + } + glideRatio = 0.0f; + samplesSinceLastClear = 0; } + else { + glideLastSampleTime = currentTime; + glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); + glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); + glideBufferIndex = (glideBufferIndex + 1) % bufferSize; - if (glideBufferCurrentSize >= minimumSampleCount) { - // Calculate glide ratio using the samples - glideRatio = calculateGlideRatioFromBuffer(glideBuffer, glideBufferCurrentSize); + if (samplesSinceLastClear < bufferSize) { + samplesSinceLastClear++; + } + + if (samplesSinceLastClear >= minimumSampleCount) { + // Calculate glide ratio using the samples + glideRatio = calculateGlideRatioFromBuffer(glideBuffer, bufferSize); + } + else { + glideRatio = 0.0f; // Not enough samples yet + } } } From 2bda14881cd424e13e29125b1051cb3115896f81 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:56:14 +0200 Subject: [PATCH 13/25] fix: update glideLastSampleTime correctly in osdDrawSingleElement function --- src/main/io/osd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 1b259053b75..ad3fa0973e6 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2206,7 +2206,7 @@ static bool osdDrawSingleElement(uint8_t item) if (currentTime - glideLastSampleTime >= sampleIntervalMs) { // Record a new sample - + glideLastSampleTime = currentTime; if (!isDataValidForGlideRatio()) { // Conditions not valid for glide ratio, reset buffer for (uint16_t i = 0; i < bufferSize; i++) { @@ -2217,7 +2217,6 @@ static bool osdDrawSingleElement(uint8_t item) samplesSinceLastClear = 0; } else { - glideLastSampleTime = currentTime; glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); glideBufferIndex = (glideBufferIndex + 1) % bufferSize; From 34a521db9f7178e7ae686199300f850d22f907f1 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:56:26 +0200 Subject: [PATCH 14/25] fix: update ascent duration check in isDataValidForGlideRatio function to 4 seconds --- src/main/io/osd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index ad3fa0973e6..337044b95a3 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1875,11 +1875,11 @@ static uint16_t ensureGlideBufferAllocated(uint16_t requiredSize) } static bool isDataValidForGlideRatio() { - // Check if we have been ascending for more than 5 seconds, which would indicate that the glide ratio is not valid + // Check if we have been ascending for more than 4 seconds, which would indicate that the glide ratio is not valid static timeMs_t lastDescentTime = 0; if (getEstimatedActualVelocity(Z) < 0) { // Descending lastDescentTime = millis(); - } else if (millis() - lastDescentTime > 5000) { // Ascending for more than 5 seconds + } else if (millis() - lastDescentTime > 4000) { // Ascending for more than 4 seconds return false; } From b84f15452f3ccbe32419356077c68a3f247dfa2b Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:00:25 +0200 Subject: [PATCH 15/25] style: update function signature of isDataValidForGlideRatio to include void parameter --- src/main/io/osd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 337044b95a3..a08bf8c545d 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1874,7 +1874,7 @@ static uint16_t ensureGlideBufferAllocated(uint16_t requiredSize) return requiredSize; } -static bool isDataValidForGlideRatio() { +static bool isDataValidForGlideRatio(void) { // Check if we have been ascending for more than 4 seconds, which would indicate that the glide ratio is not valid static timeMs_t lastDescentTime = 0; if (getEstimatedActualVelocity(Z) < 0) { // Descending From cd6c566de35c743b2003c198ad5e8d5f308679d1 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:20:04 +0200 Subject: [PATCH 16/25] cleanup: remove now unused hardcoded glide sample rate and time frame constants --- src/main/io/osd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index a08bf8c545d..b4c440383b9 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -198,8 +198,6 @@ typedef struct glidePositionSample_s { int32_t altitude_cm; // Altitude } glidePositionSample_t; -static const uint8_t glideSampleRate = 2; // 2Hz -static const uint8_t glideSampleTimeFrame = 10; // seconds static const uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid // Lazy-allocated glide buffer From 3a1ae63a28543b2079d18c4a2896e6e810b12af4 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 19:01:46 +0200 Subject: [PATCH 17/25] fix: calculate glide ratio using only the valid samples collected in osdDrawSingleElement function --- src/main/io/osd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index b4c440383b9..7b707577b39 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1877,7 +1877,7 @@ static bool isDataValidForGlideRatio(void) { static timeMs_t lastDescentTime = 0; if (getEstimatedActualVelocity(Z) < 0) { // Descending lastDescentTime = millis(); - } else if (millis() - lastDescentTime > 4000) { // Ascending for more than 4 seconds + } else if (millis() - lastDescentTime > 4000) { // Not descending for more than 4 seconds return false; } @@ -2213,6 +2213,7 @@ static bool osdDrawSingleElement(uint8_t item) } glideRatio = 0.0f; samplesSinceLastClear = 0; + glideBufferIndex = 0; } else { glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); @@ -2224,8 +2225,8 @@ static bool osdDrawSingleElement(uint8_t item) } if (samplesSinceLastClear >= minimumSampleCount) { - // Calculate glide ratio using the samples - glideRatio = calculateGlideRatioFromBuffer(glideBuffer, bufferSize); + // Calculate glide ratio using only the valid samples collected + glideRatio = calculateGlideRatioFromBuffer(glideBuffer, samplesSinceLastClear); } else { glideRatio = 0.0f; // Not enough samples yet From 61989d3f470f3f63791fe36a06755190e71414b9 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 19:10:18 +0200 Subject: [PATCH 18/25] refactor: adjust minimum sample count calculation to be relative to total sample count --- src/main/io/osd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 7b707577b39..0aae4581536 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -198,7 +198,6 @@ typedef struct glidePositionSample_s { int32_t altitude_cm; // Altitude } glidePositionSample_t; -static const uint8_t minimumSampleCount = 5; // Minimum number of samples in the timeframe to consider the glide slope valid // Lazy-allocated glide buffer static glidePositionSample_t *glideBuffer = NULL; @@ -2185,6 +2184,7 @@ static bool osdDrawSingleElement(uint8_t item) uint8_t sampleRate = osdConfig()->glide_sample_rate; uint8_t timeFrame = osdConfig()->glide_sample_time_frame; const uint16_t requiredBufferSize = sampleRate * timeFrame; + const uint8_t minimumSampleCount = requiredBufferSize / 4; // Require at least a quarter of the buffer to be filled with valid samples before showing a glide ratio uint16_t bufferSize = ensureGlideBufferAllocated(requiredBufferSize); if (bufferSize == 0) { From c170fce213ead5283dfdf5d7368e849983694929 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 19:10:31 +0200 Subject: [PATCH 19/25] fix: clarify comment regarding glide slope naming consistency fix: update error display in osdDrawSingleElement function --- src/main/io/osd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 0aae4581536..ac251fe1424 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -2179,7 +2179,7 @@ static bool osdDrawSingleElement(uint8_t item) case OSD_GLIDESLOPE: { // Note: the element was originally named "Glide Slope" but actually shows the glide ratio - // The original naming is conserved in places to retain compatibility + // The original naming is conserved in places to retain compatibility but otherwise the code refers to it as glide ratio uint8_t sampleRate = osdConfig()->glide_sample_rate; uint8_t timeFrame = osdConfig()->glide_sample_time_frame; @@ -2190,7 +2190,9 @@ static bool osdDrawSingleElement(uint8_t item) if (bufferSize == 0) { // Allocation failed, display error buff[0] = SYM_GLIDESLOPE; - buff[1] = buff[2] = buff[3] = '-'; + buff[1] = 'E'; + buff[2] = 'R'; + buff[3] = 'R'; buff[4] = '\0'; break; } From 9130d2c2815ea73d59395d86dc9760a691ce3a6b Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:40:57 +0200 Subject: [PATCH 20/25] refactor: handle glide slope calculation outside of the glide slope draw call and make glideslope available for other functions to allow glideTime and glideDistance to use it for their calculations --- src/main/io/osd.c | 135 +++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index ac251fe1424..0932e07df2e 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -204,6 +204,11 @@ static glidePositionSample_t *glideBuffer = NULL; static uint16_t glideBufferAllocatedSize = 0; static uint16_t glideBufferCurrentSize = 0; +// Calculated glide ratio (distance per unit altitude descent) +// Available for use by multiple OSD elements +static float currentGlideRatio = 0.0f; +static bool useGlideElement = false; // Whether any glide element is enabled, used to determine whether glide ratio calculation needs to be performed + static statistic_t stats; static timeUs_t resumeRefreshAt = 0; @@ -1941,6 +1946,69 @@ static float calculateGlideRatioFromBuffer(const glidePositionSample_t *buffer, return 0.0f; // Out of reasonable range } +// Update glide ratio calculation +// Called regularly to maintain glide ratio buffer regardless of OSD element visibility +// This ensures glide ratio is available for all OSD elements that need it +static void updateGlideRatioCalculation(void) { + uint8_t sampleRate = osdConfig()->glide_sample_rate; + uint8_t timeFrame = osdConfig()->glide_sample_time_frame; + const uint16_t requiredBufferSize = sampleRate * timeFrame; + const uint8_t minimumSampleCount = requiredBufferSize / 4; + + uint16_t bufferSize = ensureGlideBufferAllocated(requiredBufferSize); + + if (bufferSize == 0) { + // Allocation failed + currentGlideRatio = 0.0f; + return; + } + + static uint8_t glideBufferIndex = 0; + static timeMs_t glideLastSampleTime = 0; + static uint8_t samplesSinceLastClear = 0; + const timeMs_t currentTime = millis(); + const uint16_t sampleIntervalMs = 1000 / sampleRate; + + if (currentTime - glideLastSampleTime >= sampleIntervalMs) { + // Record a new sample + glideLastSampleTime = currentTime; + if (!isDataValidForGlideRatio()) { + // Conditions not valid for glide ratio, reset buffer + for (uint16_t i = 0; i < bufferSize; i++) { + glideBuffer[i].distance_cm = 0; + glideBuffer[i].altitude_cm = 0; + } + currentGlideRatio = 0.0f; + samplesSinceLastClear = 0; + glideBufferIndex = 0; + } + else { + glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); + glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); + glideBufferIndex = (glideBufferIndex + 1) % bufferSize; + + if (samplesSinceLastClear < bufferSize) { + samplesSinceLastClear++; + } + + if (samplesSinceLastClear >= minimumSampleCount) { + // Calculate glide ratio using only the valid samples collected + currentGlideRatio = calculateGlideRatioFromBuffer(glideBuffer, samplesSinceLastClear); + } + else { + currentGlideRatio = 0.0f; // Not enough samples yet + } + } + } +} + +static void enableGlideRatioCalculation(void) { + if (!useGlideElement) { + useGlideElement = true; + updateGlideRatioCalculation(); // Start calculation immediately when element is enabled + } +} + static bool osdDrawSingleElement(uint8_t item) { uint16_t pos = osdLayoutsConfig()->item_pos[currentLayout][item]; @@ -2178,67 +2246,10 @@ static bool osdDrawSingleElement(uint8_t item) case OSD_GLIDESLOPE: { - // Note: the element was originally named "Glide Slope" but actually shows the glide ratio - // The original naming is conserved in places to retain compatibility but otherwise the code refers to it as glide ratio - - uint8_t sampleRate = osdConfig()->glide_sample_rate; - uint8_t timeFrame = osdConfig()->glide_sample_time_frame; - const uint16_t requiredBufferSize = sampleRate * timeFrame; - const uint8_t minimumSampleCount = requiredBufferSize / 4; // Require at least a quarter of the buffer to be filled with valid samples before showing a glide ratio - uint16_t bufferSize = ensureGlideBufferAllocated(requiredBufferSize); - - if (bufferSize == 0) { - // Allocation failed, display error - buff[0] = SYM_GLIDESLOPE; - buff[1] = 'E'; - buff[2] = 'R'; - buff[3] = 'R'; - buff[4] = '\0'; - break; - } - - static uint8_t glideBufferIndex = 0; - static timeMs_t glideLastSampleTime = 0; - static uint8_t samplesSinceLastClear = 0; - const timeMs_t currentTime = millis(); - const uint16_t sampleIntervalMs = 1000 / sampleRate; - static float glideRatio = 0.0f; - - if (currentTime - glideLastSampleTime >= sampleIntervalMs) { - // Record a new sample - glideLastSampleTime = currentTime; - if (!isDataValidForGlideRatio()) { - // Conditions not valid for glide ratio, reset buffer - for (uint16_t i = 0; i < bufferSize; i++) { - glideBuffer[i].distance_cm = 0; - glideBuffer[i].altitude_cm = 0; - } - glideRatio = 0.0f; - samplesSinceLastClear = 0; - glideBufferIndex = 0; - } - else { - glideBuffer[glideBufferIndex].distance_cm = getTotalTravelDistance(); - glideBuffer[glideBufferIndex].altitude_cm = osdGetAltitude(); - glideBufferIndex = (glideBufferIndex + 1) % bufferSize; - - if (samplesSinceLastClear < bufferSize) { - samplesSinceLastClear++; - } - - if (samplesSinceLastClear >= minimumSampleCount) { - // Calculate glide ratio using only the valid samples collected - glideRatio = calculateGlideRatioFromBuffer(glideBuffer, samplesSinceLastClear); - } - else { - glideRatio = 0.0f; // Not enough samples yet - } - } - } - + enableGlideRatioCalculation(); // Ensure glide ratio calculation is running if this element is enabled buff[0] = SYM_GLIDESLOPE; - if (glideRatio > 0.0f && glideRatio < 100.0f) { - osdFormatCentiNumber(buff + 1, glideRatio * 100.0f, 0, 2, 0, 3, false); + if (currentGlideRatio > 0.0f && currentGlideRatio < 100.0f) { + osdFormatCentiNumber(buff + 1, currentGlideRatio * 100.0f, 0, 2, 0, 3, false); } else { buff[1] = buff[2] = buff[3] = '-'; } @@ -6024,6 +6035,10 @@ static bool osdIsPageDownStickCommandHeld(void) static void osdRefresh(timeUs_t currentTimeUs) { osdFilterData(currentTimeUs); + + if (useGlideElement) { + updateGlideRatioCalculation(); + } #ifdef USE_CMS if (IS_RC_MODE_ACTIVE(BOXOSD) && (!cmsInMenu) && !(osdConfig()->osd_failsafe_switch_layout && FLIGHT_MODE(FAILSAFE_MODE))) { From fbf506049b411ecb21e9c5e72ec1e045e381dcf7 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:06:47 +0200 Subject: [PATCH 21/25] refactor: update glide time calculation to use glide ratio if available refactor: enhance glide range calculation with current glide ratio fix: call enableGlideRatioCalculation in all osd elements using it --- src/main/io/osd.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 0932e07df2e..c05f85b4dff 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1326,21 +1326,16 @@ static inline int32_t osdGetAltitudeMsl(void) } uint16_t osdGetRemainingGlideTime(void) { - float value = getEstimatedActualVelocity(Z); - static pt1Filter_t glideTimeFilterState; - const timeMs_t curTimeMs = millis(); - static timeMs_t glideTimeUpdatedMs; - - value = pt1FilterApply4(&glideTimeFilterState, isnormal(value) ? value : 0, 0.5, MS2S(curTimeMs - glideTimeUpdatedMs)); - glideTimeUpdatedMs = curTimeMs; - - if (value < 0) { - value = osdGetAltitude() / abs((int)value); - } else { - value = 0; + // Use glide ratio if available and valid + uint16_t glideTime = 0; + if (currentGlideRatio > 0.0f) { + int32_t altitude = osdGetAltitude(); + int16_t groundSpeed = gpsSol.groundSpeed; + if (altitude > 0 && groundSpeed > 0) { + glideTime = (uint16_t)((float)altitude * currentGlideRatio / groundSpeed); + } } - - return (uint16_t)roundf(value); + return glideTime; } static bool osdIsHeadingValid(void) @@ -3330,6 +3325,7 @@ static bool osdDrawSingleElement(uint8_t item) } case OSD_GLIDE_TIME_REMAINING: { + enableGlideRatioCalculation(); uint16_t glideTime = osdGetRemainingGlideTime(); buff[0] = SYM_GLIDE_MINS; if (glideTime > 0) { @@ -3350,14 +3346,18 @@ static bool osdDrawSingleElement(uint8_t item) } case OSD_GLIDE_RANGE: { - uint16_t glideSeconds = osdGetRemainingGlideTime(); + enableGlideRatioCalculation(); + int32_t altitude = osdGetAltitude(); buff[0] = SYM_GLIDE_DIST; - if (glideSeconds > 0) { - uint32_t glideRangeCM = glideSeconds * gpsSol.groundSpeed; - osdFormatDistanceSymbol(buff + 1, glideRangeCM, 0, 3); - } else { - tfp_sprintf(buff + 1, "%s%c", "---", SYM_BLANK); + if (currentGlideRatio <= 0.0f || altitude <= 0) { + tfp_sprintf(buff, "%s%c", "---", SYM_BLANK); buff[5] = '\0'; + break; + } + else + { + int32_t glideRangeCm = (int32_t)(currentGlideRatio * altitude); + osdFormatDistanceSymbol(buff + 1, glideRangeCm, 0, 3); } break; } From 5bb46b561459528a09d8479b7b254ac4aef876ed Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:17:53 +0200 Subject: [PATCH 22/25] fix: ensure glide sample rate and time frame default to valid values if misconfigured --- src/main/io/osd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index c05f85b4dff..6207e4c3183 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1945,8 +1945,8 @@ static float calculateGlideRatioFromBuffer(const glidePositionSample_t *buffer, // Called regularly to maintain glide ratio buffer regardless of OSD element visibility // This ensures glide ratio is available for all OSD elements that need it static void updateGlideRatioCalculation(void) { - uint8_t sampleRate = osdConfig()->glide_sample_rate; - uint8_t timeFrame = osdConfig()->glide_sample_time_frame; + uint8_t sampleRate = osdConfig()->glide_sample_rate > 0 ? osdConfig()->glide_sample_rate : 1; // Default to 1 sample/sec if misconfigured + uint8_t timeFrame = osdConfig()->glide_sample_time_frame > 0 ? osdConfig()->glide_sample_time_frame : 5; // Default to 5 seconds if misconfigured const uint16_t requiredBufferSize = sampleRate * timeFrame; const uint8_t minimumSampleCount = requiredBufferSize / 4; From 8be6fa113bf75833715f06720d697504358d5605 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:21:57 +0200 Subject: [PATCH 23/25] fix: free glide buffer when required size is zero to prevent memory leaks and return early --- src/main/io/osd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 6207e4c3183..3694b20411a 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1849,6 +1849,15 @@ static uint16_t ensureGlideBufferAllocated(uint16_t requiredSize) if (requiredSize > MAX_GLIDE_BUFFER_SIZE) { requiredSize = MAX_GLIDE_BUFFER_SIZE; } + + if (requiredSize == 0) { + // Free buffer if no longer needed + free(glideBuffer); + glideBuffer = NULL; + glideBufferAllocatedSize = 0; + glideBufferCurrentSize = 0; + return 0; + } // If already allocated with correct size, return it if (glideBuffer != NULL && glideBufferAllocatedSize == requiredSize) { From f26a2bc77f8355c0cf3061db63c4b59f961b7df3 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:30:10 +0200 Subject: [PATCH 24/25] fix: reset sampling state when buffer size changes to ensure accurate glide ratio calculations and prevent out of bounds array access --- src/main/io/osd.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 3694b20411a..87e27d911ac 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -1959,6 +1959,7 @@ static void updateGlideRatioCalculation(void) { const uint16_t requiredBufferSize = sampleRate * timeFrame; const uint8_t minimumSampleCount = requiredBufferSize / 4; + static uint16_t previousBufferSize = 0; uint16_t bufferSize = ensureGlideBufferAllocated(requiredBufferSize); if (bufferSize == 0) { @@ -1973,6 +1974,14 @@ static void updateGlideRatioCalculation(void) { const timeMs_t currentTime = millis(); const uint16_t sampleIntervalMs = 1000 / sampleRate; + // Reset sampling state if buffer size changed + if (bufferSize != previousBufferSize) { + previousBufferSize = bufferSize; + glideBufferIndex = 0; + samplesSinceLastClear = 0; + glideLastSampleTime = 0; // Reset to take sample immediately after resize + } + if (currentTime - glideLastSampleTime >= sampleIntervalMs) { // Record a new sample glideLastSampleTime = currentTime; From 4c8991267f719bf228c6ffcad1eeb8a0b3fdaeb6 Mon Sep 17 00:00:00 2001 From: y-decimal <83334510+y-decimal@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:41:10 +0200 Subject: [PATCH 25/25] fix: correct buffer offset for glide distance display to ensure proper formatting --- src/main/io/osd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/io/osd.c b/src/main/io/osd.c index 87e27d911ac..853f822e7ec 100644 --- a/src/main/io/osd.c +++ b/src/main/io/osd.c @@ -3368,7 +3368,7 @@ static bool osdDrawSingleElement(uint8_t item) int32_t altitude = osdGetAltitude(); buff[0] = SYM_GLIDE_DIST; if (currentGlideRatio <= 0.0f || altitude <= 0) { - tfp_sprintf(buff, "%s%c", "---", SYM_BLANK); + tfp_sprintf(buff + 1, "%s%c", "---", SYM_BLANK); buff[5] = '\0'; break; }