Skip to content

Hide the RX downlink power element when the link does not report it - #11914

Open
Raffi1202 wants to merge 2 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:fix/crsf-downlink-tx-power
Open

Raffi1202 wants to merge 2 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:fix/crsf-downlink-tx-power

Conversation

@Raffi1202

@Raffi1202 Raffi1202 commented Sep 10, 2026

Copy link
Copy Markdown

Problem

On an ExpressLRS receiver (BetaFPV SuperD 2.4, INAV 8.0.1, Matek H743 V3) the OSD element OSD_RX_POWER_DOWNLINK shows 0 mW although the receiver transmits telemetry at 100 mW. The reporter expected the real value. Fixes #11136.

Cause

src/main/io/osd.c:2851 on maintenance-10.x prints rxLinkStatistics.downlinkTXPower unconditionally. The field is only written by src/main/fc/fc_msp.c:3475 (MSP2_COMMON_SET_MSP_RC_INFO) and src/main/fc/fc_mavlink.c:350 (mLRS radio link information). The CRSF parser handles only link statistics frame 0x14 (src/main/rx/crsf.c:235-250), whose payload (crsf.c:113-124) carries uplinkTXPower but no downlink power, so on CRSF the field keeps its initial 0.

Change

In osdDrawSingleElement() the OSD_RX_POWER_DOWNLINK case blanks the six-character field and returns false when downlinkTXPower == 0, so osdDrawNextElement() (osd.c:4270) moves on to the next element. Zero already means "not reported" on the other paths: mavlinkDbmToMilliwatts() (fc_mavlink.c:214-221) returns 0 for INT8_MAX and for anything at or below 0 dBm. The blank write (fe5ea81) removes a previously drawn value when an MSP or MAVLink link stops reporting it. docs/OSD.md gets a note on the element.

Test

Not run on hardware or SITL. Cause verified by reading crsf.c:113-124 and crsf.c:235-250 on maintenance-10.x: downlinkTXPower has no CRSF writer. Built by fork CI: pending. The upstream "Build firmware" run is waiting for maintainer approval (https://github.com/iNavFlight/inav/actions/runs/34619647336). Qodo's single finding (stale characters after the value drops to 0) is covered by the blank write in fe5ea81.

Flash / RAM

Not measured yet. The upstream firmware CI has not been released for this PR, so no size report exists.

Docs

docs/OSD.md: the OSD_RX_POWER_DOWNLINK row now states that the element is hidden unless the RC link reports the receiver's transmit power (MSP and MAVLink do, CRSF does not).

The receiver transmit power is only written by the MSP and MAVLink RC
paths. The CRSF link statistics frame 0x14 has no such field and no
other CRSF frame is parsed for it, so with an ExpressLRS receiver the
element showed a permanent 0 mW.

ExpressLRS never sends the optional link statistics RX frame 0x1C that
would carry a power value, so parsing it would not populate the element
either. A power of 0 already means "not reported" on the other paths,
so skip drawing the element in that case.

Fixes iNavFlight#11136
@Raffi1202
Raffi1202 marked this pull request as ready for review September 11, 2026 15:45
@qodo-code-review

Copy link
Copy Markdown
Contributor

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Stale receiver power remains after reporting stops ✓ Resolved 🐞 Bug ≡ Correctness
Description
osdDrawSingleElement() returns before writing or clearing the element when downlinkTXPower
becomes zero. After an MSP or MAVLink link previously reports a nonzero value and then loses that
field, normal OSD refreshes skip this element while displayClearScreen() is only used for
full-screen redraws, so the old power can remain visible.
Code

src/main/io/osd.c[R2850-2851]

+            if (rxLinkStatistics.downlinkTXPower == 0)
+                return false;
Evidence
The new zero-value branch returns before the common displayWriteWithAttr() call. The normal OSD
loop calls osdDrawNextElement() on each refresh, while the only nearby screen clear is guarded by
fullRedraw, so a previously rendered value is not removed when the element becomes unavailable.

src/main/io/osd.c[2846-2857]
src/main/io/osd.c[4121-4126]
src/main/io/osd.c[5992-6000]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `downlinkTXPower` changes from a reported nonzero value to zero, the early return skips the normal display write, leaving the old receiver power text on screen until an unrelated full-screen clear.
### Fix Focus Areas
- src/main/io/osd.c[2846-2857]
- src/main/io/osd.c[4125-4126]
### Recommended Fix
When the value is unknown, clear or overwrite the element's display region before returning false, using the display API's established blanking behavior. Preserve the existing false return so `osdDrawNextElement()` continues to skip drawing unavailable telemetry.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can switch off images and animations for a plain-text comment

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/main/io/osd.c Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Hide unavailable receiver downlink power from the OSD

🐞 Bug fix 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Hide receiver downlink power when link statistics report an unknown zero value.
• Document that only MSP and MAVLink RC links provide receiver transmit power.
Diagram

graph TD
  MSP["MSP / MAVLink"] -->|"power value"| Stats["Link Statistics"] --> Check{"Power reported?"}
  CRSF["CRSF Link"] -->|"zero / unknown"| Stats
  Check -->|"yes"| Render["RX Power OSD"]
  Check -->|"no"| Skip["Skip element"]
Loading
High-Level Assessment

The guard is the appropriate minimal fix because zero is already the established unknown sentinel and the OSD scheduler already interprets false as not drawable. Parsing CRSF frame 0x1C would not help ExpressLRS users because that frame is not emitted, while introducing a separate capability flag would require unnecessary cross-protocol changes for the same result.

Files changed (2) +6 / -1

Bug fix (1) +5 / -0
osd.cSkip unavailable receiver power element +5/-0

Skip unavailable receiver power element

• Returns false from the receiver downlink power rendering case when downlinkTXPower is zero. This prevents unsupported links such as CRSF and ExpressLRS from permanently displaying 0 mW.

src/main/io/osd.c

Documentation (1) +1 / -1
OSD.mdDocument receiver downlink power availability +1/-1

Document receiver downlink power availability

• Explains that the element remains hidden unless the RC link reports receiver transmit power. Clarifies that MSP and MAVLink provide the value while CRSF does not.

docs/OSD.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant