Release 0.2.0: fix Display Options crash with voice prompts on

Screen Dim passed a plain literal ('100%'/'50%'/...) to
voicePromptsAppendLanguageString(), which derives the prompt index from the
string's offset within the language table; a foreign pointer produced a garbage
index and crashed (only with voice on). Route the value through
voicePromptsAppendString() instead. Also move the 3-bit dim level's high bit off
legacy option bit 2 to bit 29 and clamp the level against the option arrays.

Bump version to 0.2.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcus Kida 2026-07-07 15:41:59 +02:00
parent 734b861917
commit 1c59622a77
5 changed files with 34 additions and 6 deletions

View file

@ -7,6 +7,17 @@ single running list until the first versioned release.
## Unreleased ## Unreleased
_Nothing yet._
## 0.2.0
- **Fix crash** opening Display Options with **voice announcements on**: the Screen
Dim value ("100%"/"50%"/…) is a plain literal, but the shared menu code fed it to
`voicePromptsAppendLanguageString()`, which derives the prompt index from the
string's offset within the language table — a foreign pointer produced a garbage
index and crashed. The value now goes through `voicePromptsAppendString()`. Also
moved the dim-level high bit off a low legacy option bit (bit 2 → 29) and clamped
the level so it can never index past the option arrays.
- **7-segment frequency font:** inactive segments are now off (background) instead - **7-segment frequency font:** inactive segments are now off (background) instead
of faintly lit — no dim "ghosting". "MHz" now matches the frequency colour, and of faintly lit — no dim "ghosting". "MHz" now matches the frequency colour, and
there's 1px more space between the RX and TX frequency lines. there's 1px more space between the RX and TX frequency lines.

View file

@ -5,9 +5,9 @@
#define _FREETRX_VERSION_H_ #define _FREETRX_VERSION_H_
#define FREETRX_VERSION_MAJOR 0 #define FREETRX_VERSION_MAJOR 0
#define FREETRX_VERSION_MINOR 1 #define FREETRX_VERSION_MINOR 2
#define FREETRX_VERSION_PATCH 0 #define FREETRX_VERSION_PATCH 0
#define FREETRX_VERSION "0.1.0" #define FREETRX_VERSION "0.2.0"
#endif // _FREETRX_VERSION_H_ #endif // _FREETRX_VERSION_H_

View file

@ -129,7 +129,7 @@ typedef enum
{ {
BIT_INVERSE_VIDEO = (SETTINGS_BITS_BANK_0 | (1 << 0)), BIT_INVERSE_VIDEO = (SETTINGS_BITS_BANK_0 | (1 << 0)),
BIT_PTT_LATCH = (SETTINGS_BITS_BANK_0 | (1 << 1)), BIT_PTT_LATCH = (SETTINGS_BITS_BANK_0 | (1 << 1)),
BIT_SCREEN_DIM_2 = (SETTINGS_BITS_BANK_0 | (1 << 2)), // high bit of the 3-bit screen-dim level BIT_UNUSED_2 = (SETTINGS_BITS_BANK_0 | (1 << 2)),
BIT_BATTERY_VOLTAGE_IN_HEADER = (SETTINGS_BITS_BANK_0 | (1 << 3)), BIT_BATTERY_VOLTAGE_IN_HEADER = (SETTINGS_BITS_BANK_0 | (1 << 3)),
BIT_SETTINGS_UPDATED = (SETTINGS_BITS_BANK_0 | (1 << 4)), BIT_SETTINGS_UPDATED = (SETTINGS_BITS_BANK_0 | (1 << 4)),
BIT_TX_RX_FREQ_LOCK = (SETTINGS_BITS_BANK_0 | (1 << 5)), BIT_TX_RX_FREQ_LOCK = (SETTINGS_BITS_BANK_0 | (1 << 5)),
@ -154,6 +154,7 @@ typedef enum
#endif #endif
BIT_SECONDARY_LANGUAGE = (SETTINGS_BITS_BANK_0 | (1 << 19)), BIT_SECONDARY_LANGUAGE = (SETTINGS_BITS_BANK_0 | (1 << 19)),
BIT_SCREEN_DIM_1 = (SETTINGS_BITS_BANK_0 | (1 << 20)), // middle bit of the 3-bit screen-dim level BIT_SCREEN_DIM_1 = (SETTINGS_BITS_BANK_0 | (1 << 20)), // middle bit of the 3-bit screen-dim level
BIT_SCREEN_DIM_2 = (SETTINGS_BITS_BANK_0 | (1 << 29)), // high bit of the 3-bit screen-dim level (kept off low legacy bits)
BIT_DISPLAY_CHANNEL_DISTANCE = (SETTINGS_BITS_BANK_0 | (1 << 21)), BIT_DISPLAY_CHANNEL_DISTANCE = (SETTINGS_BITS_BANK_0 | (1 << 21)),
#if defined(PLATFORM_MD2017) #if defined(PLATFORM_MD2017)
BIT_TRACKBALL_ENABLED = (SETTINGS_BITS_BANK_0 | (1 << 22)), BIT_TRACKBALL_ENABLED = (SETTINGS_BITS_BANK_0 | (1 << 22)),

View file

@ -607,7 +607,9 @@ bool settingsIsOptionBitSet(bitfieldOptions_t bit)
// no new settings field (existing codeplugs keep both bits clear = SCREEN_DIM_OFF). // no new settings field (existing codeplugs keep both bits clear = SCREEN_DIM_OFF).
uint8_t settingsGetScreenDimLevel(void) uint8_t settingsGetScreenDimLevel(void)
{ {
return (settingsIsOptionBitSet(BIT_SCREEN_DIM_0) ? 1 : 0) | (settingsIsOptionBitSet(BIT_SCREEN_DIM_1) ? 2 : 0) | (settingsIsOptionBitSet(BIT_SCREEN_DIM_2) ? 4 : 0); uint8_t level = (settingsIsOptionBitSet(BIT_SCREEN_DIM_0) ? 1 : 0) | (settingsIsOptionBitSet(BIT_SCREEN_DIM_1) ? 2 : 0) | (settingsIsOptionBitSet(BIT_SCREEN_DIM_2) ? 4 : 0);
// Never return an out-of-range level: dimOpts[]/dimPercent[] are SCREEN_DIM_NUM long.
return (level < SCREEN_DIM_NUM) ? level : SCREEN_DIM_OFF;
} }
void settingsSetScreenDimLevel(uint8_t level) void settingsSetScreenDimLevel(uint8_t level)

View file

@ -249,9 +249,23 @@ static void updateScreen(bool isFirstRun)
case DISPLAY_SCREEN_DIM: case DISPLAY_SCREEN_DIM:
{ {
const char *dimOpts[] = { currentLanguage->off, "100%", "50%", "30%", "15%" }; // The "%" values are plain string literals, not currentLanguage entries,
// so they must go through rightSideVar -> voicePromptsAppendString().
// Passing them to voicePromptsAppendLanguageString() (as the shared code
// does for rightSideConst) would treat the pointer as an offset into the
// language table and crash when voice prompts are enabled. "Off" is a real
// language string, so it can stay in rightSideConst.
const char *dimOpts[] = { NULL, "100%", "50%", "30%", "15%" };
uint8_t dimLevel = settingsGetScreenDimLevel();
leftSide = "Screen Dim"; leftSide = "Screen Dim";
rightSideConst = dimOpts[settingsGetScreenDimLevel()]; if (dimLevel == SCREEN_DIM_OFF)
{
rightSideConst = currentLanguage->off;
}
else
{
snprintf(rightSideVar, SCREEN_LINE_BUFFER_SIZE, "%s", dimOpts[dimLevel]);
}
} }
break; break;