Skip to content

feat: move GVAR to their own storage, structure and usage - #7861

Open
3djc wants to merge 3 commits into
mainfrom
3djc/gvars-rework
Open

3djc wants to merge 3 commits into
mainfrom
3djc/gvars-rework

Conversation

@3djc

@3djc 3djc commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Why

On the Outputs screen, gvars were handled differently from everywhere else. Instead of being a source like in mixes and inputs, a gvar was hidden inside the number: a few values at the top of the field's range secretly meant "GV1", "GV2" and so on, with their own special code in every screen. This makes a gvar in Min, Max and Subtrim an ordinary source, the same way mix weight and offset already work (#5220). Only the Outputs screen was affected; mixes, inputs and curves are unchanged.

What you'll notice

  • Min, Max and Subtrim are now either a number or a source (for example GV1, or an inverted gvar). Switching between the two works the same as in mixes.
  • Black & white radios: select the field and long-press ENTER to switch between number and source.
  • Color radios: use the SRC button next to the field.
  • Companion: each field has an SRC checkbox next to the value.
  • Because a gvar is now just a source, other sources can be selected in these fields too.
  • Existing models behave the same. Gvar limits saved by older versions load and work as before, with the same clamping (±150% for min and max, ±100% for subtrim).

Good to know

  • A model that uses a source for a limit won't load that limit correctly on older firmware. Models with only plain numbers are unaffected.
  • Gvar names aren't shown on the black & white limits screens; the gvar number is, as in mixes (for example G1).
  • Lua scripts using model.getOutput() / model.setOutput() get a source as ±(2048 + source number). Plain numbers are unchanged.

Format (for reviewers)

  • The field holds a number or a source: 12 bits, 11 for the value and 1 flag. The mix field is smaller (10 bits plus the flag) and cannot hold limit values, which reach ±1000. LimitData stays the same size.
  • Numbers keep their meaning (0.1% units, min and max stored relative to ∓100%). Sources are written like every other source, for example "gv(2)" or "!gv(8)". The old 1-based GV1 / -GV1 forms are still read, so no file conversion is needed.
  • The GV_RANGE macros, GET_GVAR and GVarNumberEdit are removed, so the gvar count no longer has to fit inside the limit fields' value range.
  • The generated YAML tables were regenerated for all targets.

Also fixed

  • In older model files, a mix weight or offset of GV10 to GV15 was loaded as GV1.
  • Inverted telemetry, timer and TX voltage sources in mix weights and offsets could be treated as a gvar and read the wrong value.

Size

About 2.3 KB smaller on color radios, 190 bytes smaller on X7 ACCESS, and no change in RAM use.

Testing

Unit tests were added for the mixer, YAML, Lua and Companion. They pass on 19 radio targets, and I checked the B&W and colorlcd output screens in the test harness. It has been lightly tested on colorlcd

Miscelaneous

Beyond Outputs, the change touches shared code in three ways:

  • Removed: the in-field gvar helpers and macros are gone. Nothing else used them.
  • Fixes in shared code: GV10 to GV15 in old mix weights, and inverted telemetry, timer and TX voltage sources in mix weights, expo and curve values. I mention both in the PR.
  • Shared screen widget: SourceNumberEdit is the editor mixes and inputs use. I added a wide mode and made its offset parameter work, which it ignored before. For mixes and inputs it behaves as before.

Things I didn't touch to avoid scope creep, but that could be added based on feedbacks:

  • The "Adjust GVAR" special function has its own modes: constant, source, gvar and increment/decrement.
  • Flight modes store a gvar as "use the value from flight mode N" when it holds a number above 1024.
    - The curves screen lists gvars at the end of the curves, as a quirk of the B&W menu.

@3djc
3djc marked this pull request as draft October 4, 2026 07:04
@3djc
3djc marked this pull request as ready for review October 4, 2026 12:38
@elecpower

Copy link
Copy Markdown
Collaborator

I have a refactor that does this and goes even further for Companion as part of the work on radio conversions that has stalled waiting on firmware and boards refactor.
My refactor treats gvars, curves and numbers as Companion RawSources thereby removing the hybrid class using magic numbers just like you have done for gvars. And you have tackled the yaml on both sides too.
So it's a big tick from me.

@pfeerick pfeerick added enhancement ✨ New feature or request rn: feature Feature to be highlighted in release notes labels Oct 4, 2026
@pfeerick

pfeerick commented Oct 4, 2026

Copy link
Copy Markdown
Member

This combined with #2096 will be a much needed major overhaul for GVs across the board... both in how they are written to file, and how used (from telemetry sensors through to everywhere else)... I look forward to trying it out! :)

This "out of scope" point is a little misleading...

  • The curves screen lists gvars at the end of the curves, as a quirk of the B&W menu.

... as this OpenTX UI code was never enabled, but is still material for it's own cleanup PR though - it is not used, and won't compile anyway.

@pfeerick pfeerick added this to the 3.0 milestone Oct 4, 2026
@philmoz

philmoz commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator
  • Lua scripts using model.getOutput() / model.setOutput() get a source as ±(2048 + source number). Plain numbers are unchanged.

Isn't this going to potentially break existing Lua scripts?

@pfeerick

pfeerick commented Oct 5, 2026

Copy link
Copy Markdown
Member

True. However, a major version change is when any backward incompatible and API breaking changes are expected and allowed.

@3djc

3djc commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

I understand what you are saying about the api change, but I think the risk is low because the current api didn't mention how to get to gvar, and this is how you can before the PR:

Capture d’écran 2026-10-05 à 08 20 19

Unlikely to be used given the nightmare is was, this makes it clearer I think

These targets were added on main after this branch was started, so they
still used the old LimitData layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pfeerick pfeerick added the rn: warning Warning needed in release notes label Oct 30, 2026
@pfeerick

pfeerick commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

@3djc Do you think perhaps on bw it should behave like the weight/offsets options (i.e long press when source or constant brings up the popup menu, which lets you pick source/constant/invert, etc)? i.e. something like this? Is fine as it is on colorlcd

pfeerick.user/0001-fix-bw-long-press-on-output-limit-source-opens-sourc.patch
From 14f04b3279190c8d2121bbd4c533d0c794ad755a Mon Sep 17 00:00:00 2001
From: Peter Feerick <5500713+pfeerick@users.noreply.github.com>
Date: Sat, 31 Oct 2026 00:03:18 +0000
Subject: [PATCH] fix(bw): long press on output limit source opens source popup

Min, max and subtrim on B&W radios hard-toggled between a constant and
GV1 on long press, so there was no way to invert a source or pick
Constant via the menu. Route them through the same SourceNumVal popup
used for weight and offset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---
 .../src/gui/common/stdlcd/widgets_common.cpp  | 29 ++++++++++---------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/radio/src/gui/common/stdlcd/widgets_common.cpp b/radio/src/gui/common/stdlcd/widgets_common.cpp
index 57c11d890f..339d950345 100644
--- a/radio/src/gui/common/stdlcd/widgets_common.cpp
+++ b/radio/src/gui/common/stdlcd/widgets_common.cpp
@@ -85,32 +85,33 @@ uint16_t editSrcVarFieldValue(coord_t x, coord_t y, const char* title, uint16_t
   return value;
 }
 
+extern int checkIncDecSelection;
+
 bool editLimitNumSource(coord_t x, coord_t y, uint16_t& value, LcdFlags attr,
                         event_t event)
 {
   LimitNumVal v;
   v.rawValue = value;
 
-  if ((attr & INVERS) && event == EVT_KEY_LONG(KEY_ENTER)) {
-    killEvents(event);
-    s_editMode = !s_editMode;
-    value = v.isSource ? makeLimitNumVal(0)
-                       : makeLimitNumVal(modelGVEnabled() ? MIXSRC_FIRST_GVAR : 1, true);
-    v.rawValue = value;
-    storageDirty(EE_MODEL);
+  // Constants are edited by the caller, only handle the source popup here
+  if ((attr & INVERS) && (v.isSource || event == EVT_KEY_LONG(KEY_ENTER) ||
+                          checkIncDecSelection != 0)) {
+    SourceNumVal s;
+    s.rawValue = checkIncDec(event, makeSourceNumVal(v.isSource ? v.value : 0, v.isSource),
+                             0, 0, 1, MIXSRC_LAST,
+                             EE_MODEL | INCDEC_SOURCE_VALUE | INCDEC_SOURCE_INVERT |
+                                 NO_INCDEC_MARKS,
+                             isSourceAvailable);
+    if (v.isSource || s.isSource) {
+      value = makeLimitNumVal(s.isSource ? s.value : 0, s.isSource);
+      v.rawValue = value;
+    }
   }
 
   if (!v.isSource) return false;
 
   attr &= ~PREC1;
   drawSource(x, y, v.value, attr);
-  if (attr & INVERS) {
-    v.value = checkIncDec(event, v.value, 1, MIXSRC_LAST,
-                          EE_MODEL | INCDEC_SOURCE | INCDEC_SOURCE_INVERT |
-                              NO_INCDEC_MARKS,
-                          isSourceAvailable);
-    value = v.rawValue;
-  }
   return true;
 }
 
-- 
2.54.0

This branch has not been deployed

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

Labels

enhancement ✨ New feature or request rn: feature Feature to be highlighted in release notes rn: warning Warning needed in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants