/* * Copyright (C) 2021-2025 Roger Clark, VK3KYY / G4KYF * Daniel Caujolle-Bert, F1RMB * * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation, * incorporation in a commercial product or incorporation into a product or project which allows commercial use. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "functions/rxPowerSaving.h" #include "functions/trx.h" #include "functions/ticks.h" #include #include "usb/usb_com.h" #define LOW_SPEED_CLOCK_ECO_THRESHOLD 2 static ecoPhase_t rxPowerSavingState = ECOPHASE_POWERSAVE_INACTIVE; static ticksTimer_t ecoPhaseTimer = { 0, 0 }; volatile static int powerSavingLevel = 1; static bool hrc6000IsPoweredOff = false; bool rxPowerSavingIsRxOn(void) { return (rxPowerSavingState != ECOPHASE_POWERSAVE_ACTIVE___RX_IS_OFF); } void rxPowerSavingSetLevel(int newLevel) { if (powerSavingLevel != newLevel) { if (newLevel == 0) { rxPowerSavingSetState(ECOPHASE_POWERSAVE_INACTIVE); } powerSavingLevel = newLevel; } } int rxPowerSavingGetLevel(void) { return powerSavingLevel; } static void resumeBeepAndC6000Tasks(void) { vTaskResume(hrc6000Task.Handle); hrc6000Task.Running = true; hrc6000Task.AliveCount = TASK_FLAGGED_ALIVE; vTaskResume(beepTask.Handle); beepTask.Running = true; beepTask.AliveCount = TASK_FLAGGED_ALIVE; //HRC6000FlushMusic(); //G4EML Needed after restarting the HRC6000 Task to prevent missing DMR audio; } static void suspendBeepAndC6000Tasks(void) { vTaskSuspend(beepTask.Handle); beepTask.Running = false; vTaskSuspend(hrc6000Task.Handle); hrc6000Task.Running = false; } void rxPowerSavingSetState(ecoPhase_t newState) { if (rxPowerSavingState != newState) { if (rxPowerSavingState == ECOPHASE_POWERSAVE_ACTIVE___RX_IS_OFF) { hrc6000IsPoweredOff = trxPowerUpDownRxAndC6000(true, hrc6000IsPoweredOff, false); } rxPowerSavingState = newState; // Avoid to instantly jump to power saving mode if (rxPowerSavingState == ECOPHASE_POWERSAVE_INACTIVE) { if (powerSavingLevel >= LOW_SPEED_CLOCK_ECO_THRESHOLD) { clockManagerSetRunMode(kAPP_PowerModeRun, CLOCK_MANAGER_SPEED_RUN); resumeBeepAndC6000Tasks(); } ticksTimerStart(&ecoPhaseTimer, ((12 - (MIN(powerSavingLevel, 4) * 2)) * 1000)); } } } void rxPowerSavingTick(uiEvent_t *ev, bool hasSignal) { if ((settingsUsbMode != USB_MODE_HOTSPOT) || (rxPowerSavingState != ECOPHASE_POWERSAVE_INACTIVE)) { if (USB_DeviceIsResetting() || isCompressingAMBE || hasSignal || trxTransmissionEnabled || trxIsTransmitting || (menuSystemGetCurrentMenuNumber() == UI_TX_SCREEN) || (menuSystemGetCurrentMenuNumber() == UI_CPS) || (uiDataGlobal.Scan.active && uiDataGlobal.Scan.scanType == SCAN_TYPE_NORMAL_STEP) || ev->hasEvent) { if (rxPowerSavingState != ECOPHASE_POWERSAVE_INACTIVE) { if (rxPowerSavingState == ECOPHASE_POWERSAVE_ACTIVE___RX_IS_OFF) { hrc6000IsPoweredOff = trxPowerUpDownRxAndC6000(true, hrc6000IsPoweredOff, false);// Power up AT1846S, C6000 and preamp } if (powerSavingLevel >= LOW_SPEED_CLOCK_ECO_THRESHOLD) { clockManagerSetRunMode(kAPP_PowerModeRun, CLOCK_MANAGER_SPEED_RUN); resumeBeepAndC6000Tasks(); } rxPowerSavingState = ECOPHASE_POWERSAVE_INACTIVE; } // Postpone entering the ECOPHASE_POWERSAVE_INACTIVE ticksTimerStart(&ecoPhaseTimer, ((12 - (MIN(powerSavingLevel, 4) * 2)) * 1000)); } else { if (ticksTimerHasExpired(&ecoPhaseTimer) && ((powerSavingLevel > 0) && (codeplugChannelGetFlag(currentChannelData, CHANNEL_FLAG_NO_ECO) == 0)) && (melody_play == NULL) && (voicePromptsIsPlaying() == false) #if defined(PLATFORM_MDUV380) || defined(PLATFORM_RT84_DM1701) || defined(PLATFORM_MD2017) && (voxIsEnabled() == false) #endif ) { int rxDuration = (130 - (10 * powerSavingLevel)); switch(rxPowerSavingState) { case ECOPHASE_POWERSAVE_INACTIVE:// wait before shutting down ticksTimerStart(&ecoPhaseTimer, ((12 - (MIN(powerSavingLevel, 4) * 2)) * 1000)); rxPowerSavingState = ECOPHASE_POWERSAVE_WAIT_START; break; case ECOPHASE_POWERSAVE_WAIT_START: if ((powerSavingLevel >= LOW_SPEED_CLOCK_ECO_THRESHOLD) && (SETTINGS_GPS_MODE_GET(nonVolatileSettings) <= GPS_MODE_OFF)) { suspendBeepAndC6000Tasks(); clockManagerSetRunMode(kAPP_PowerModeRun, CLOCK_MANAGER_RUN_ECO_POWER_MODE); } rxPowerSavingState = ECOPHASE_POWERSAVE_ACTIVE___RX_IS_ON; // drop through case ECOPHASE_POWERSAVE_ACTIVE___RX_IS_ON: hrc6000IsPoweredOff = trxPowerUpDownRxAndC6000(false, (powerSavingLevel > 1), false);// Power down AT1846S, C6000 and preamp ticksTimerStart(&ecoPhaseTimer, (rxDuration * (1 << (powerSavingLevel - 1)))); rxPowerSavingState = ECOPHASE_POWERSAVE_ACTIVE___RX_IS_OFF; break; case ECOPHASE_POWERSAVE_ACTIVE___RX_IS_OFF: //USB_DEBUG_printf("ECOPHASE_POWERSAVE_ACTIVE___RX_IS_ON\n"); hrc6000IsPoweredOff = trxPowerUpDownRxAndC6000(true, hrc6000IsPoweredOff, false);// Power up AT1846S, C6000 and preamps ticksTimerStart(&ecoPhaseTimer, (rxDuration * 1)); trxPostponeReadRSSIAndNoise(0); // Give it a bit of time, after powering up, before checking the RSSI and Noise values rxPowerSavingState = ECOPHASE_POWERSAVE_ACTIVE___RX_IS_ON; break; } } } } }