Skip to content

Add adjCenter and adjScale to Adjustments Tab#4863

Open
spatzengr wants to merge 1 commit intobetaflight:masterfrom
spatzengr:AdjTab-Center_Scale
Open

Add adjCenter and adjScale to Adjustments Tab#4863
spatzengr wants to merge 1 commit intobetaflight:masterfrom
spatzengr:AdjTab-Center_Scale

Conversation

@spatzengr
Copy link
Contributor

@spatzengr spatzengr commented Feb 13, 2026

image

Summary by CodeRabbit

  • New Features

    • Added Adjustment Center and Adjustment Scale controls in the Adjustments UI so each adjustment can store, edit and persist center and scale values; UI layout updated to accommodate the new controls.
    • Persistence and transmission updated to include these values while remaining compatible with older protocol versions.
  • Documentation (Localization)

    • Added English labels/translations for the new Adjustment Center and Adjustment Scale.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds two new adjustment fields—adjustmentCenter and adjustmentScale—across localization, the Adjustments UI, VirtualFC defaults, and MSP parsing/encoding (conditionally enabled for API_VERSION_1_48+), increasing ADJUSTMENT_RANGES item size from 6→8 bytes when supported.

Changes

Cohort / File(s) Summary
Localization
locales/en/messages.json
Added adjustmentsColumnAdjustmentCenter and adjustmentsColumnAdjustmentScale translation keys.
Adjustments UI Component
src/components/tabs/AdjustmentsTab.vue
Added header columns and per-row inputs for adjustmentCenter and adjustmentScale; bound fields to adjustment items; updated load/save logic, grid layout, and styles; inputs respect enabled/disabled states.
Virtual FC model
src/js/VirtualFC.js
Initialize adjustmentCenter and adjustmentScale (default 0) on ADJUSTMENT_RANGES items.
MSP serialization / parsing
src/js/msp/MSPHelper.js
Compute bytesPerItem as 8 when API_VERSION_1_48+ (else 6); parse conditional adjustmentCenter/adjustmentScale; encode them when sending for API_VERSION_1_48+.

Sequence Diagram(s)

sequenceDiagram
    participant UI as "AdjustmentsTab (UI)"
    participant Model as "VirtualFC"
    participant MSP as "MSPHelper"
    participant FC as "Flight Controller"

    rect rgba(200,200,255,0.5)
    UI->>Model: request adjustments
    Model-->>UI: return adjustments (include center, scale)
    end

    rect rgba(200,255,200,0.5)
    UI->>UI: user edits center/scale
    UI->>Model: update adjustment item (center, scale)
    end

    rect rgba(255,200,200,0.5)
    UI->>MSP: saveAdjustments (encode ADJUSTMENT_RANGES as 8 bytes/item if supported)
    MSP->>FC: send MSP_SET_ADJUSTMENT_RANGE payload
    FC-->>MSP: ACK/response
    MSP-->>UI: confirmation
    end

    rect rgba(255,255,200,0.5)
    FC->>MSP: MSP_ADJUSTMENT_RANGES (8 bytes/item if API>=1.48)
    MSP->>Model: parse and populate center/scale
    Model-->>UI: refresh adjustments
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Needs coordination with firmware, RN: FEATURE, RN: UI, Vue

Suggested reviewers

  • nerdCopter
  • blckmn
  • haslinghuis
🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description consists only of an image with no accompanying text or structured information following the required template format. Add a descriptive text summary explaining the changes, motivation, and testing performed. Follow the repository's PR description template structure to provide context beyond the visual changes shown in the image.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding two new adjustment parameters (center and scale) to the Adjustments Tab UI.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@spatzengr
Copy link
Contributor Author

@coderabbitai, please write an overview, description and review this PR.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Get PR details
gh pr view 4863 --json title,body,additions,deletions,changedFiles,files

# Get the PR diff to see what was changed
gh pr diff 4863

# Get the list of files changed
gh pr view 4863 --json files --jq '.files[].path'

Length of output: 5878


@spatzengr, I'll help you write the overview and description for this PR, and then provide a review of the changes.

PR Overview

This PR enhances the Adjustments Tab by adding support for two new configuration parameters: Adjustment Center and Adjustment Scale. These fields allow users to fine-tune the behavior of adjustment functions by configuring center point and scaling values directly from the configurator interface.

PR Description

Changes Made

This PR introduces UI controls and data handling for two new adjustment parameters:

  1. Adjustment Center (adjustmentCenter) - Configures the center point for adjustments (range: 0-255)
  2. Adjustment Scale (adjustmentScale) - Configures the scaling factor for adjustments (range: 0-255)

Technical Implementation

UI Enhancements:

  • Added two new columns to the Adjustments Tab grid layout
  • Implemented number input fields for both parameters with validation (min: 0, max: 255)
  • Inputs are automatically disabled when the adjustment slot is disabled
  • Updated grid layout from 5 to 7 columns to accommodate the new fields

Localization:

  • Added English translations for the new column headers:
    • adjustmentsColumnAdjustmentCenter: "adjustment center"
    • adjustmentsColumnAdjustmentScale: "adjustment scale"

Data Handling:

  • Properties are properly initialized with default value of 0 in all relevant contexts
  • Data persists correctly when saving/loading adjustment ranges
  • Fallback values ensure backward compatibility with existing configurations

User Experience

Users can now configure adjustment center and scale values directly in the Adjustments Tab, providing more granular control over adjustment functions without needing to use the CLI.


Now let me review the implementation:

Code Review

✅ Strengths

  1. Consistent Implementation: The new properties are properly initialized in all three locations where adjustment ranges are created/updated (lines 415, 467, 480, 497)

  2. Proper Vue Patterns: Uses v-model.number modifier to ensure numeric values, preventing string-type issues

  3. Accessibility: Includes data-label attributes for responsive design/mobile views

  4. Input Validation: Min/max attributes (0-255) provide proper bounds checking

  5. Code Style: Follows existing patterns and maintains consistency with other fields in the component

💡 Suggestions

  1. Consider adding step attribute: The number inputs might benefit from step="1" to make increment/decrement buttons work intuitively:
<input
    type="number"
    step="1"
    v-model.number="adjustment.adjustmentCenter"
    ...
/>
  1. Optional: Add tooltips/help text: Since these are advanced parameters, consider adding tooltips or help text explaining what center and scale do for users unfamiliar with these concepts.

  2. Consider input validation feedback: While min/max attributes exist, you might want to add visual feedback when users enter out-of-range values.

📋 Overall Assessment

The implementation is solid and production-ready. The code is clean, follows Vue best practices, maintains consistency with the existing codebase, and properly handles all edge cases (disabled state, default values, backward compatibility). The grid layout changes are correctly applied to both the header and adjustment rows.

Recommendation: ✅ Approve pending minor optional enhancements

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/js/msp/MSPHelper.js (1)

1014-1028: ⚠️ Potential issue | 🔴 Critical

Critical: byte count divisor must be /8, not /9.

The loop reads exactly 8 bytes per item: the original 6 fields (slotIndex, auxChannelIndex, start, end, adjustmentFunction, auxSwitchChannelIndex) plus the two new fields (adjustmentCenter, adjustmentScale). Dividing by 9 will cause incorrect item counts and frame misalignment during parsing.

Update line 1014:

-                    const adjustmentRangeCount = data.byteLength / 9; // 9 bytes per item.
+                    const adjustmentRangeCount = data.byteLength / 8; // 8 bytes per item.

(Note: the SET encoding at line 2632 correctly sends 9 bytes because it includes adjustmentRangeIndex as a leading byte; the GET response has no per-item index.)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/js/msp/MSPHelper.js (1)

1014-1028: ⚠️ Potential issue | 🔴 Critical

Add API version guard for MSP_ADJUSTMENT_RANGES structure size change.

The code unconditionally reads 8 bytes per adjustment range, but lacks version gating for the two newer fields (adjustmentCenter, adjustmentScale). If connected to firmware versions that send only 6 bytes per item, data.byteLength / 8 will compute the wrong item count, causing the two extra readU8() calls to read into subsequent items' data and corrupt all parsed entries.

This pattern is inconsistent with how the rest of MSPHelper.js handles protocol changes—20+ similar features are guarded with semver.gte(FC.CONFIG.apiVersion, API_VERSION_X) checks. The sender code at lines 2639–2640 also uses || 0 fallback, suggesting these fields were added after the base structure.

Determine which firmware API version introduced these two fields (check betaflight firmware's msp.c struct), then guard the additional reads and byte-count calculation accordingly:

Example approach
                case MSPCodes.MSP_ADJUSTMENT_RANGES:
                    FC.ADJUSTMENT_RANGES = [];

-                    const adjustmentRangeCount = data.byteLength / 8;
+                    const bytesPerItem = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_4X) ? 8 : 6;
+                    const adjustmentRangeCount = data.byteLength / bytesPerItem;

                    for (let i = 0; i < adjustmentRangeCount; i++) {
                        const adjustmentRange = {
                            slotIndex: data.readU8(),
                            auxChannelIndex: data.readU8(),
                            range: {
                                start: 900 + data.readU8() * 25,
                                end: 900 + data.readU8() * 25,
                            },
                            adjustmentFunction: data.readU8(),
                            auxSwitchChannelIndex: data.readU8(),
-                            adjustmentCenter: data.readU8(),
-                            adjustmentScale: data.readU8(),
+                            adjustmentCenter: semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_4X) ? data.readU8() : 0,
+                            adjustmentScale: semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_4X) ? data.readU8() : 0,
                        };

Replace API_VERSION_1_4X with the actual API version from betaflight firmware that introduced these fields.

🤖 Fix all issues with AI agents
In `@src/js/msp/MSPHelper.js`:
- Around line 2638-2640: The encoder for MSP_SET_ADJUSTMENT_RANGE is adding two
bytes with .push8(adjustmentRange.auxSwitchChannelIndex) and
.push8(adjustmentRange.adjustmentCenter || 0) without checking firmware API
version; mirror the parsing-side safeguard by wrapping those .push8() calls with
the same API version check used when parsing MSP_SET_ADJUSTMENT_RANGE so older
firmware won't receive the extra bytes—locate the build/encode code in
MSPHelper.js where MSP_SET_ADJUSTMENT_RANGE is composed and gate the two .push8
calls with the existing API version conditional used elsewhere in this file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/js/msp/MSPHelper.js`:
- Line 1014: The inline comment on the bytesPerItem const is inverted relative
to the ternary; update the comment next to "const bytesPerItem =
semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48) ? 8 : 6" so it correctly
states that the code returns 8 bytes per item when apiVersion is >=
API_VERSION_1_48 and 6 bytes otherwise (note that adjustmentCenter and
adjustmentScale were added in 1.48).
- Around line 2639-2644: Add the missing semicolon after the chained call to
buffer.push8(adjustmentRange.auxSwitchChannelIndex) and correct the indentation
of the subsequent if block: ensure the if (semver.gte(FC.CONFIG.apiVersion,
API_VERSION_1_48)) { ... } block is indented to align with the previous
statement (8 spaces like other chains) and that the chain before it ends with a
semicolon; adjust surrounding lines in the MSPHelper.js code where
buffer.push8(...) and the semver.gte check occur to match the project's
indentation style.

Comment on lines 2639 to 2644
.push8(adjustmentRange.auxSwitchChannelIndex)
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) {
buffer
.push8(adjustmentRange.adjustmentCenter || 0)
.push8(adjustmentRange.adjustmentScale || 0);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix indentation and add missing semicolon after the chain.

ESLint reports incorrect indentation (12 spaces instead of 8 for the if block). Also, the .push8(adjustmentRange.auxSwitchChannelIndex) expression on line 2639 is missing its terminating semicolon — it works, but every other chain in this function ends with one.

Suggested fix
-            .push8(adjustmentRange.auxSwitchChannelIndex)
-            if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) {
-                buffer
-                    .push8(adjustmentRange.adjustmentCenter || 0)
-                    .push8(adjustmentRange.adjustmentScale || 0);
-            }
+            .push8(adjustmentRange.auxSwitchChannelIndex);
+        if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) {
+            buffer
+                .push8(adjustmentRange.adjustmentCenter || 0)
+                .push8(adjustmentRange.adjustmentScale || 0);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.push8(adjustmentRange.auxSwitchChannelIndex)
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) {
buffer
.push8(adjustmentRange.adjustmentCenter || 0)
.push8(adjustmentRange.adjustmentScale || 0);
}
.push8(adjustmentRange.auxSwitchChannelIndex);
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) {
buffer
.push8(adjustmentRange.adjustmentCenter || 0)
.push8(adjustmentRange.adjustmentScale || 0);
}
🧰 Tools
🪛 ESLint

[error] 2640-2640: Expected indentation of 8 spaces but found 12.

(indent)


[error] 2641-2641: Expected indentation of 12 spaces but found 16.

(indent)


[error] 2642-2642: Expected indentation of 16 spaces but found 20.

(indent)


[error] 2643-2643: Expected indentation of 16 spaces but found 20.

(indent)


[error] 2644-2644: Expected indentation of 8 spaces but found 12.

(indent)

🤖 Prompt for AI Agents
In `@src/js/msp/MSPHelper.js` around lines 2639 - 2644, Add the missing semicolon
after the chained call to buffer.push8(adjustmentRange.auxSwitchChannelIndex)
and correct the indentation of the subsequent if block: ensure the if
(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_48)) { ... } block is indented
to align with the previous statement (8 spaces like other chains) and that the
chain before it ends with a semicolon; adjust surrounding lines in the
MSPHelper.js code where buffer.push8(...) and the semver.gte check occur to
match the project's indentation style.

Update MSPHelper.js

Update AdjustmentsTab.vue

Update messages.json
@sonarqubecloud
Copy link

@github-actions
Copy link
Contributor

🎉 Do you want to test this code? 🎉

⚠️ CAUTION: The build may be unstable and result in corrupted configurations or data loss. Use only for testing! ⚠️

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