Fix: green LED flicker between red mute flashes during a DMR QSO

The DMR RX handler re-asserts the green LED whenever it reads it off, racing the
main-loop mute clear, so green flickered between the red flashes. Add a
LedGreenSuppress() hold in the LED driver: while muted the green LED is forced
off (the re-assert becomes a no-op); on un-mute the hold is released and green is
restored from the current RX state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcus Kida 2026-07-12 13:15:23 +02:00
parent 63a833269a
commit 5ac77c5ae9
3 changed files with 39 additions and 7 deletions

View file

@ -7,6 +7,10 @@ single running list until the first versioned release.
## Unreleased ## Unreleased
- **Fix:** green LED **flickering** between the red flashes while muted during a DMR
QSO. The DMR RX handler re-asserts the green LED as soon as it reads it off, racing
the main-loop mute clear; the green LED is now **held off at the driver** for the
whole mute (and released on un-mute), so only the red flash shows.
- **`screenshot.sh`** — a one-command wrapper around the OpenGD77 screen grabber - **`screenshot.sh`** — a one-command wrapper around the OpenGD77 screen grabber
that auto-detects the serial port and sets up a self-contained Python venv that auto-detects the serial port and sets up a self-contained Python venv
(pyserial + pillow) on first run. Saves to `screenshots/`. (pyserial + pillow) on first run. Saves to `screenshots/`.

View file

@ -1441,18 +1441,27 @@ void applicationMainTask(void)
if (audioAmpIsMuted() || (lastVolume == -99)) // explicit mute or volume knob fully down if (audioAmpIsMuted() || (lastVolume == -99)) // explicit mute or volume knob fully down
{ {
if (!muteFlashActive)
{
// Hold the green LED off for the whole mute, so the DMR RX handler
// (which re-asserts green as soon as it reads it off) can't make it
// flicker green between the red flashes.
LedGreenSuppress(true);
muteFlashActive = true;
}
bool flashOn = ((ticksGetMillis() % 2000) < 500); bool flashOn = ((ticksGetMillis() % 2000) < 500);
LedWrite(LED_GREEN, 0);
LedWrite(LED_RED, (flashOn ? 1 : 0)); LedWrite(LED_RED, (flashOn ? 1 : 0));
muteFlashActive = true;
} }
else if (muteFlashActive) else if (muteFlashActive)
{ {
// Just unmuted: stop the red flash and restore the green LED to the // Just unmuted: release the green hold, stop the red flash and restore
// current RX state, so a QSO in progress lights green again instead of // the green LED to the current RX state, so a QSO in progress lights
// staying dark. Green is normally lit for an active DMR slot (matching // green again instead of staying dark. Green is normally lit for an
// our filter) or a received FM/digital signal; if nothing is being // active DMR slot (matching our filter) or a received FM/digital signal;
// received it stays off. The normal RX code then keeps it correct. // if nothing is being received it stays off. The normal RX code then
// keeps it correct.
LedGreenSuppress(false);
bool rxGreen = (slotState == DMR_STATE_RX_1) || (slotState == DMR_STATE_RX_2) || bool rxGreen = (slotState == DMR_STATE_RX_1) || (slotState == DMR_STATE_RX_2) ||
currentRadioDevice->analogSignalReceived || currentRadioDevice->digitalSignalReceived; currentRadioDevice->analogSignalReceived || currentRadioDevice->digitalSignalReceived;
LedWrite(LED_RED, 0); LedWrite(LED_RED, 0);

View file

@ -48,9 +48,28 @@ void LEDsInit(void)
#endif #endif
} }
// When set, the green LED is held off: any LedWrite(LED_GREEN, 1) is forced to 0.
// Used while muted so the DMR RX handler (which re-asserts green whenever it reads
// it as 0) can't make the green LED flicker between the red mute flashes.
static volatile bool greenLedSuppressed = false;
void LedGreenSuppress(bool suppress)
{
greenLedSuppressed = suppress;
if (suppress)
{
LedWrite(LED_GREEN, 0); // force it off now
}
}
void LedWrite(LEDs_t theLED, uint8_t output) void LedWrite(LEDs_t theLED, uint8_t output)
{ {
#if ! defined(PLATFORM_GD77S) #if ! defined(PLATFORM_GD77S)
if ((theLED == LED_GREEN) && greenLedSuppressed)
{
output = 0; // green is held off (e.g. while muted)
}
LEDsState[theLED] = output; LEDsState[theLED] = output;
if (settingsIsOptionBitSet(BIT_ALL_LEDS_DISABLED) == 0) if (settingsIsOptionBitSet(BIT_ALL_LEDS_DISABLED) == 0)