-
Notifications
You must be signed in to change notification settings - Fork 421
Add OSD tab entries for the profile name elements #2750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Raffi1202
wants to merge
10
commits into
iNavFlight:maintenance-10.x
Choose a base branch
from
Raffi1202:feature/profile-name-osd
base: maintenance-10.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
250c813
Show profile names in the header dropdowns and add name fields
68ea960
Give the profile name labels fallback text
8686ea8
Add OSD tab entries for the profile name elements
14eef7b
Fix profile-name imports in MSP regression tests and cover refresh re…
Raffi1202 367ba4d
Merge profile-name regression test fixes into the OSD branch
Raffi1202 031bc72
fix: preview the active unnamed profile slot in OSD
Raffi1202 054a590
fix: refresh OSD previews when profile names arrive
Raffi1202 6acc482
Reapply profile names after language changes
Raffi1202 c52cc30
Address Sonar findings in the review fixes
Raffi1202 cfd5a00
Drop the MSP regression test changes from this PR
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| 'use strict'; | ||
|
|
||
| // Decoder for MSP2_INAV_PROFILE_NAMES: the user-defined names of every | ||
| // control, battery and mixer profile slot in one reply. | ||
| // | ||
| // uint8 maxNameLength (MAX_PROFILE_NAME_LENGTH in the firmware) | ||
| // uint8 controlProfileCount, then per slot: uint8 length + that many bytes | ||
| // uint8 batteryProfileCount, then per slot as above | ||
| // uint8 mixerProfileCount, then per slot as above | ||
| // | ||
| // An unnamed slot has length 0 and decodes to an empty string. | ||
|
|
||
| function readNameList(data, cursor) { | ||
| if (cursor.offset >= data.byteLength) { | ||
| return null; | ||
| } | ||
|
|
||
| const count = data.getUint8(cursor.offset++); | ||
| const names = []; | ||
|
|
||
| for (let i = 0; i < count; i++) { | ||
| if (cursor.offset >= data.byteLength) { | ||
| return null; | ||
| } | ||
| const length = data.getUint8(cursor.offset++); | ||
| if (cursor.offset + length > data.byteLength) { | ||
| return null; | ||
| } | ||
| let name = ''; | ||
| for (let c = 0; c < length; c++) { | ||
| name += String.fromCodePoint(data.getUint8(cursor.offset++)); | ||
| } | ||
| names.push(name); | ||
| } | ||
|
|
||
| return names; | ||
| } | ||
|
|
||
| /** | ||
| * @param {DataView} data payload of an MSP2_INAV_PROFILE_NAMES reply | ||
| * @returns {{maxLength: number, control: string[], battery: string[], mixer: string[]}|null} | ||
| * null when the payload is truncated or malformed | ||
| */ | ||
| export function parseProfileNames(data) { | ||
| if (!data || data.byteLength < 4) { | ||
| return null; | ||
| } | ||
|
|
||
| const cursor = { offset: 0 }; | ||
| const maxLength = data.getUint8(cursor.offset++); | ||
| const control = readNameList(data, cursor); | ||
| const battery = readNameList(data, cursor); | ||
| const mixer = readNameList(data, cursor); | ||
|
|
||
| if (control === null || battery === null || mixer === null || cursor.offset !== data.byteLength) { | ||
| return null; | ||
| } | ||
|
|
||
| return { maxLength: maxLength, control: control, battery: battery, mixer: mixer }; | ||
| } | ||
|
|
||
| /** | ||
| * Label for a profile selector entry: the translated base label, plus the | ||
| * user's name when the slot has one. | ||
| */ | ||
| export function profileOptionLabel(baseLabel, name) { | ||
| return name ? baseLabel + ': ' + name : baseLabel; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #!/usr/bin/env node | ||
| /** | ||
| * Tests for parseProfileNames() / profileOptionLabel() (js/profileNames.js), | ||
| * the decoder for MSP2_INAV_PROFILE_NAMES used to label the header profile | ||
| * dropdowns. | ||
| */ | ||
|
|
||
| import { test } from 'node:test'; | ||
| import assert from 'node:assert/strict'; | ||
| import { parseProfileNames, profileOptionLabel } from '../js/profileNames.js'; | ||
|
|
||
| function buildPayload(maxLength, lists) { | ||
| const bytes = [maxLength]; | ||
| for (const list of lists) { | ||
| bytes.push(list.length); | ||
| for (const name of list) { | ||
| bytes.push(name.length); | ||
| for (const ch of name) { | ||
| bytes.push(ch.charCodeAt(0)); | ||
| } | ||
| } | ||
| } | ||
| return new DataView(Uint8Array.from(bytes).buffer); | ||
| } | ||
|
|
||
| test('decodes three name lists with empty slots', () => { | ||
| const view = buildPayload(12, [['Cruise', '', 'Sport'], ['4S', '6S HV', ''], ['Quad', 'Plane']]); | ||
|
|
||
| assert.deepEqual(parseProfileNames(view), { | ||
| maxLength: 12, | ||
| control: ['Cruise', '', 'Sport'], | ||
| battery: ['4S', '6S HV', ''], | ||
| mixer: ['Quad', 'Plane'], | ||
| }); | ||
| }); | ||
|
|
||
| test('handles a single mixer profile and all-empty names', () => { | ||
| const view = buildPayload(12, [['', '', ''], ['', '', ''], ['']]); | ||
| const names = parseProfileNames(view); | ||
|
|
||
| assert.equal(names.mixer.length, 1); | ||
| assert.deepEqual(names.control, ['', '', '']); | ||
| }); | ||
|
|
||
| test('rejects truncated, trailing and empty payloads', () => { | ||
| const good = buildPayload(12, [['A'], ['B'], ['C']]); | ||
|
|
||
| assert.equal(parseProfileNames(new DataView(good.buffer.slice(0, good.byteLength - 1))), null); | ||
|
|
||
| const trailing = new Uint8Array(good.byteLength + 1); | ||
| trailing.set(new Uint8Array(good.buffer)); | ||
| assert.equal(parseProfileNames(new DataView(trailing.buffer)), null); | ||
|
|
||
| assert.equal(parseProfileNames(new DataView(new ArrayBuffer(0))), null); | ||
| assert.equal(parseProfileNames(null), null); | ||
| }); | ||
|
|
||
| test('option label appends the name only when there is one', () => { | ||
| assert.equal(profileOptionLabel('Control Profile 1', 'Cruise'), 'Control Profile 1: Cruise'); | ||
| assert.equal(profileOptionLabel('Control Profile 2', ''), 'Control Profile 2'); | ||
| assert.equal(profileOptionLabel('Control Profile 3', undefined), 'Control Profile 3'); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.