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
- **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
that auto-detects the serial port and sets up a self-contained Python venv
(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 (!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);
LedWrite(LED_GREEN, 0);
LedWrite(LED_RED, (flashOn ? 1 : 0));
muteFlashActive = true;
}
else if (muteFlashActive)
{
// Just unmuted: stop the red flash and restore the green LED to the
// current RX state, so a QSO in progress lights green again instead of
// staying dark. Green is normally lit for an active DMR slot (matching
// our filter) or a received FM/digital signal; if nothing is being
// received it stays off. The normal RX code then keeps it correct.
// Just unmuted: release the green hold, stop the red flash and restore
// the green LED to the current RX state, so a QSO in progress lights
// green again instead of staying dark. Green is normally lit for an
// active DMR slot (matching our filter) or a received FM/digital signal;
// 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) ||
currentRadioDevice->analogSignalReceived || currentRadioDevice->digitalSignalReceived;
LedWrite(LED_RED, 0);

View file

@ -48,9 +48,28 @@ void LEDsInit(void)
#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)
{
#if ! defined(PLATFORM_GD77S)
if ((theLED == LED_GREEN) && greenLedSuppressed)
{
output = 0; // green is held off (e.g. while muted)
}
LEDsState[theLED] = output;
if (settingsIsOptionBitSet(BIT_ALL_LEDS_DISABLED) == 0)