uv-k5-firmware-custom/app/menu.c

1330 lines
27 KiB
C

/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "app/dtmf.h"
#include "app/generic.h"
#include "app/menu.h"
#include "app/scanner.h"
#include "audio.h"
#include "board.h"
#include "bsp/dp32g030/gpio.h"
#include "driver/backlight.h"
#include "driver/gpio.h"
#include "driver/keyboard.h"
#include "frequencies.h"
#include "misc.h"
#include "settings.h"
#include "sram-overlay.h"
#include "ui/inputbox.h"
#include "ui/menu.h"
#include "ui/ui.h"
#ifndef DISABLE_VOICE
static const VOICE_ID_t MenuVoices[] =
{
VOICE_ID_SQUELCH,
VOICE_ID_FREQUENCY_STEP,
VOICE_ID_POWER,
VOICE_ID_DCS,
VOICE_ID_CTCSS,
VOICE_ID_DCS,
VOICE_ID_CTCSS,
VOICE_ID_FREQUENCY_DIRECTION,
VOICE_ID_OFFSET_FREQUENCY,
VOICE_ID_CHANNEL_BANDWIDTH,
VOICE_ID_SCRAMBLER_ON,
VOICE_ID_BUSY_LOCKOUT,
VOICE_ID_MEMORY_CHANNEL,
VOICE_ID_SAVE_MODE,
VOICE_ID_VOX,
VOICE_ID_INVALID,
VOICE_ID_DUAL_STANDBY,
VOICE_ID_INVALID,
VOICE_ID_BEEP_PROMPT,
VOICE_ID_TRANSMIT_OVER_TIME,
// #ifndef DISABLE_VOICE
VOICE_ID_VOICE_PROMPT,
// #endif
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
#ifndef DISABLE_ALARM
VOICE_ID_INVALID,
#endif
VOICE_ID_ANI_CODE,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
#ifndef DISABLE_NOAA
VOICE_ID_INVALID,
#endif
VOICE_ID_DELETE_CHANNEL,
VOICE_ID_INITIALISATION,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID,
VOICE_ID_INVALID
};
#endif
void MENU_StartCssScan(int8_t Direction)
{
gCssScanMode = CSS_SCAN_MODE_SCANNING;
gMenuScrollDirection = Direction;
RADIO_SelectVfos();
MENU_SelectNextCode();
ScanPauseDelayIn10msec = 50;
gScheduleScanListen = false;
}
void MENU_StopCssScan(void)
{
gCssScanMode = CSS_SCAN_MODE_OFF;
RADIO_SetupRegisters(true);
}
int MENU_GetLimits(uint8_t Cursor, uint8_t *pMin, uint8_t *pMax)
{
switch (Cursor)
{
case MENU_SQL:
*pMin = 0;
*pMax = 9;
break;
case MENU_STEP:
if (gTxVfo->Band == BAND2_108MHz)
{
*pMin = 0;
*pMax = 6;
break;
}
// Fallthrough
case MENU_ABR:
case MENU_F_LOCK:
*pMin = 0;
*pMax = 5;
break;
case MENU_MDF:
#ifdef CHAN_NAME_FREQ
*pMin = 0;
*pMax = 3;
break;
#endif
// Fallthrough
case MENU_TXP:
case MENU_SFT_D:
case MENU_TDR:
case MENU_XB:
#ifndef DISABLE_VOICE
case MENU_VOICE:
#endif
case MENU_SC_REV:
case MENU_PONMSG:
case MENU_ROGER:
*pMin = 0;
*pMax = 2;
break;
case MENU_R_DCS:
case MENU_T_DCS:
*pMin = 0;
*pMax = 208;
break;
case MENU_R_CTCS:
case MENU_T_CTCS:
*pMin = 0;
*pMax = 50;
break;
case MENU_W_N:
case MENU_BCL:
case MENU_BEEP:
case MENU_AUTOLK:
case MENU_S_ADD1:
case MENU_S_ADD2:
case MENU_STE:
#ifndef DISABLE_ALARM
case MENU_AL_MOD:
#endif
case MENU_D_ST:
case MENU_D_DCD:
case MENU_AM:
#ifndef DISABLE_NOAA
case MENU_NOAA_S:
#endif
case MENU_RESET:
case MENU_350TX:
case MENU_200TX:
case MENU_500TX:
case MENU_350EN:
case MENU_SCREN:
*pMin = 0;
*pMax = 1;
break;
case MENU_SCR:
case MENU_VOX:
case MENU_TOT:
case MENU_RP_STE:
*pMin = 0;
*pMax = 10;
break;
case MENU_MEM_CH:
case MENU_1_CALL:
case MENU_SLIST1:
case MENU_SLIST2:
case MENU_DEL_CH:
*pMin = 0;
*pMax = 199;
break;
case MENU_SAVE:
case MENU_MIC:
*pMin = 0;
*pMax = 4;
break;
case MENU_S_LIST:
*pMin = 1;
*pMax = 2;
break;
case MENU_D_RSP:
case MENU_PTT_ID:
*pMin = 0;
*pMax = 3;
break;
case MENU_D_HOLD:
*pMin = 5;
*pMax = 60;
break;
case MENU_D_PRE:
*pMin = 3;
*pMax = 99;
break;
case MENU_D_LIST:
*pMin = 1;
*pMax = 16;
break;
default:
return -1;
}
return 0;
}
void MENU_AcceptSetting(void)
{
uint8_t Min;
uint8_t Max;
uint8_t Code;
FREQ_Config_t *pConfig = &gTxVfo->ConfigRX;
if (!MENU_GetLimits(gMenuCursor, &Min, &Max))
{
if (gSubMenuSelection < Min) gSubMenuSelection = Min;
else
if (gSubMenuSelection > Max) gSubMenuSelection = Max;
}
switch (gMenuCursor)
{
case MENU_SQL:
gEeprom.SQUELCH_LEVEL = gSubMenuSelection;
gRequestSaveSettings = true;
gVfoConfigureMode = VFO_CONFIGURE_1;
return;
case MENU_STEP:
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE))
{
gTxVfo->STEP_SETTING = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
}
gSubMenuSelection = gTxVfo->STEP_SETTING;
return;
case MENU_TXP:
gTxVfo->OUTPUT_POWER = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
case MENU_T_DCS:
pConfig = &gTxVfo->ConfigTX;
// Fallthrough
case MENU_R_DCS:
if (gSubMenuSelection == 0)
{
if (pConfig->CodeType != CODE_TYPE_DIGITAL && pConfig->CodeType != CODE_TYPE_REVERSE_DIGITAL)
{
gRequestSaveChannel = 1;
return;
}
Code = 0;
pConfig->CodeType = CODE_TYPE_OFF;
}
else
if (gSubMenuSelection < 105)
{
pConfig->CodeType = CODE_TYPE_DIGITAL;
Code = gSubMenuSelection - 1;
}
else
{
pConfig->CodeType = CODE_TYPE_REVERSE_DIGITAL;
Code = gSubMenuSelection - 105;
}
pConfig->Code = Code;
gRequestSaveChannel = 1;
return;
case MENU_T_CTCS:
pConfig = &gTxVfo->ConfigTX;
// Fallthrough
case MENU_R_CTCS:
if (gSubMenuSelection == 0)
{
if (pConfig->CodeType != CODE_TYPE_CONTINUOUS_TONE)
{
gRequestSaveChannel = 1;
return;
}
Code = 0;
pConfig->CodeType = CODE_TYPE_OFF;
}
else
{
pConfig->CodeType = CODE_TYPE_CONTINUOUS_TONE;
Code = gSubMenuSelection - 1;
}
pConfig->Code = Code;
gRequestSaveChannel = 1;
return;
case MENU_SFT_D:
gTxVfo->FREQUENCY_DEVIATION_SETTING = gSubMenuSelection;
gRequestSaveChannel = 1;
return;
case MENU_OFFSET:
gTxVfo->FREQUENCY_OF_DEVIATION = gSubMenuSelection;
gRequestSaveChannel = 1;
return;
case MENU_W_N:
gTxVfo->CHANNEL_BANDWIDTH = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
case MENU_SCR:
gTxVfo->SCRAMBLING_TYPE = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
case MENU_BCL:
gTxVfo->BUSY_CHANNEL_LOCK = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
case MENU_MEM_CH:
gTxVfo->CHANNEL_SAVE = gSubMenuSelection;
gRequestSaveChannel = 2;
gEeprom.MrChannel[0] = gSubMenuSelection;
return;
case MENU_SAVE:
gEeprom.BATTERY_SAVE = gSubMenuSelection;
break;
case MENU_VOX:
gEeprom.VOX_SWITCH = gSubMenuSelection != 0;
if (gEeprom.VOX_SWITCH)
gEeprom.VOX_LEVEL = gSubMenuSelection - 1;
BOARD_EEPROM_LoadMoreSettings();
gFlagReconfigureVfos = true;
gRequestSaveSettings = true;
gUpdateStatus = true;
return;
case MENU_ABR:
gEeprom.BACKLIGHT = gSubMenuSelection;
if (gSubMenuSelection == 0)
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT);
else
BACKLIGHT_TurnOn();
break;
case MENU_TDR:
gEeprom.DUAL_WATCH = gSubMenuSelection;
gFlagReconfigureVfos = true;
gRequestSaveSettings = true;
gUpdateStatus = true;
return;
case MENU_XB:
#ifndef DISABLE_NOAA
if (IS_NOAA_CHANNEL(gEeprom.ScreenChannel[0]))
return;
if (IS_NOAA_CHANNEL(gEeprom.ScreenChannel[1]))
return;
#endif
gEeprom.CROSS_BAND_RX_TX = gSubMenuSelection;
gFlagReconfigureVfos = true;
gRequestSaveSettings = true;
gUpdateStatus = true;
return;
case MENU_BEEP:
gEeprom.BEEP_CONTROL = gSubMenuSelection;
break;
case MENU_TOT:
gEeprom.TX_TIMEOUT_TIMER = gSubMenuSelection;
break;
#ifndef DISABLE_VOICE
case MENU_VOICE:
gEeprom.VOICE_PROMPT = gSubMenuSelection;
gRequestSaveSettings = true;
gUpdateStatus = true;
return;
#endif
case MENU_SC_REV:
gEeprom.SCAN_RESUME_MODE = gSubMenuSelection;
break;
case MENU_MDF:
gEeprom.CHANNEL_DISPLAY_MODE = gSubMenuSelection;
break;
case MENU_AUTOLK:
gEeprom.AUTO_KEYPAD_LOCK = gSubMenuSelection;
gKeyLockCountdown = 30;
break;
case MENU_S_ADD1:
gTxVfo->SCANLIST1_PARTICIPATION = gSubMenuSelection;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
gVfoConfigureMode = VFO_CONFIGURE_1;
gFlagResetVfos = true;
return;
case MENU_S_ADD2:
gTxVfo->SCANLIST2_PARTICIPATION = gSubMenuSelection;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
gVfoConfigureMode = VFO_CONFIGURE_1;
gFlagResetVfos = true;
return;
case MENU_STE:
gEeprom.TAIL_NOTE_ELIMINATION = gSubMenuSelection;
break;
case MENU_RP_STE:
gEeprom.REPEATER_TAIL_TONE_ELIMINATION = gSubMenuSelection;
break;
case MENU_MIC:
gEeprom.MIC_SENSITIVITY = gSubMenuSelection;
BOARD_EEPROM_LoadMoreSettings();
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
return;
case MENU_1_CALL:
gEeprom.CHAN_1_CALL = gSubMenuSelection;
break;
case MENU_S_LIST:
gEeprom.SCAN_LIST_DEFAULT = gSubMenuSelection - 1;
break;
#ifndef DISABLE_ALARM
case MENU_AL_MOD:
gEeprom.ALARM_MODE = gSubMenuSelection;
break;
#endif
case MENU_D_ST:
gEeprom.DTMF_SIDE_TONE = gSubMenuSelection;
break;
case MENU_D_RSP:
gEeprom.DTMF_DECODE_RESPONSE = gSubMenuSelection;
break;
case MENU_D_HOLD:
gEeprom.DTMF_AUTO_RESET_TIME = gSubMenuSelection;
break;
case MENU_D_PRE:
gEeprom.DTMF_PRELOAD_TIME = gSubMenuSelection * 10;
break;
case MENU_PTT_ID:
gTxVfo->DTMF_PTT_ID_TX_MODE = gSubMenuSelection;
gRequestSaveChannel = 1;
return;
case MENU_D_DCD:
gTxVfo->DTMF_DECODING_ENABLE = gSubMenuSelection;
gRequestSaveChannel = 1;
return;
case MENU_D_LIST:
gDTMFChosenContact = gSubMenuSelection - 1;
if (gIsDtmfContactValid)
{
GUI_SelectNextDisplay(DISPLAY_MAIN);
gDTMF_InputMode = true;
gDTMF_InputIndex = 3;
memcpy(gDTMF_InputBox, gDTMF_ID, 4);
gRequestDisplayScreen = DISPLAY_INVALID;
}
return;
case MENU_PONMSG:
gEeprom.POWER_ON_DISPLAY_MODE = gSubMenuSelection;
break;
case MENU_ROGER:
gEeprom.ROGER = gSubMenuSelection;
break;
case MENU_AM:
gTxVfo->AM_CHANNEL_MODE = gSubMenuSelection;
gRequestSaveChannel = 2;
return;
#ifndef DISABLE_NOAA
case MENU_NOAA_S:
gEeprom.NOAA_AUTO_SCAN = gSubMenuSelection;
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
return;
#endif
case MENU_DEL_CH:
SETTINGS_UpdateChannel(gSubMenuSelection, NULL, false);
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
return;
case MENU_RESET:
BOARD_FactoryReset(gSubMenuSelection);
return;
case MENU_350TX:
gSetting_350TX = gSubMenuSelection;
break;
case MENU_F_LOCK:
gSetting_F_LOCK = gSubMenuSelection;
break;
case MENU_200TX:
gSetting_200TX = gSubMenuSelection;
break;
case MENU_500TX:
gSetting_500TX = gSubMenuSelection;
break;
case MENU_350EN:
gSetting_350EN = gSubMenuSelection;
gRequestSaveSettings = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
return;
case MENU_SCREN:
gSetting_ScrambleEnable = gSubMenuSelection;
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
return;
default:
return;
}
gRequestSaveSettings = true;
}
void MENU_SelectNextCode(void)
{
uint8_t UpperLimit;
if (gMenuCursor == MENU_R_DCS)
UpperLimit = 208;
else
if (gMenuCursor == MENU_R_CTCS)
UpperLimit = 50;
else
return;
gSubMenuSelection = NUMBER_AddWithWraparound(gSubMenuSelection, gMenuScrollDirection, 1, UpperLimit);
if (gMenuCursor == MENU_R_DCS)
{
if (gSubMenuSelection > 104)
{
gSelectedCodeType = CODE_TYPE_REVERSE_DIGITAL;
gSelectedCode = gSubMenuSelection - 105;
}
else
{
gSelectedCodeType = CODE_TYPE_DIGITAL;
gSelectedCode = gSubMenuSelection - 1;
}
}
else
{
gSelectedCodeType = CODE_TYPE_CONTINUOUS_TONE;
gSelectedCode = gSubMenuSelection - 1;
}
RADIO_SetupRegisters(true);
ScanPauseDelayIn10msec = (gSelectedCodeType == CODE_TYPE_CONTINUOUS_TONE) ? 20 : 30;
gUpdateDisplay = true;
}
static void MENU_ClampSelection(int8_t Direction)
{
uint8_t Min;
uint8_t Max;
if (!MENU_GetLimits(gMenuCursor, &Min, &Max))
{
uint8_t Selection = gSubMenuSelection;
if (Selection < Min) Selection = Min;
else
if (Selection > Max) Selection = Max;
gSubMenuSelection = NUMBER_AddWithWraparound(Selection, Direction, Min, Max);
}
}
void MENU_ShowCurrentSetting(void)
{
switch (gMenuCursor)
{
case MENU_SQL:
gSubMenuSelection = gEeprom.SQUELCH_LEVEL;
break;
case MENU_STEP:
gSubMenuSelection = gTxVfo->STEP_SETTING;
break;
case MENU_TXP:
gSubMenuSelection = gTxVfo->OUTPUT_POWER;
break;
case MENU_R_DCS:
switch (gTxVfo->ConfigRX.CodeType)
{
case CODE_TYPE_DIGITAL:
gSubMenuSelection = gTxVfo->ConfigRX.Code + 1;
break;
case CODE_TYPE_REVERSE_DIGITAL:
gSubMenuSelection = gTxVfo->ConfigRX.Code + 105;
break;
default:
gSubMenuSelection = 0;
break;
}
break;
case MENU_RESET:
gSubMenuSelection = 0;
break;
case MENU_R_CTCS:
gSubMenuSelection = (gTxVfo->ConfigRX.CodeType == CODE_TYPE_CONTINUOUS_TONE) ? gTxVfo->ConfigRX.Code + 1 : 0;
break;
case MENU_T_DCS:
switch (gTxVfo->ConfigTX.CodeType)
{
case CODE_TYPE_DIGITAL:
gSubMenuSelection = gTxVfo->ConfigTX.Code + 1;
break;
case CODE_TYPE_REVERSE_DIGITAL:
gSubMenuSelection = gTxVfo->ConfigTX.Code + 105;
break;
default:
gSubMenuSelection = 0;
break;
}
break;
case MENU_T_CTCS:
gSubMenuSelection = (gTxVfo->ConfigTX.CodeType == CODE_TYPE_CONTINUOUS_TONE) ? gTxVfo->ConfigTX.Code + 1 : 0;
break;
case MENU_SFT_D:
gSubMenuSelection = gTxVfo->FREQUENCY_DEVIATION_SETTING;
break;
case MENU_OFFSET:
gSubMenuSelection = gTxVfo->FREQUENCY_OF_DEVIATION;
break;
case MENU_W_N:
gSubMenuSelection = gTxVfo->CHANNEL_BANDWIDTH;
break;
case MENU_SCR:
gSubMenuSelection = gTxVfo->SCRAMBLING_TYPE;
break;
case MENU_BCL:
gSubMenuSelection = gTxVfo->BUSY_CHANNEL_LOCK;
break;
case MENU_MEM_CH:
#if 0
gSubMenuSelection = gEeprom.MrChannel[0];
#else
gSubMenuSelection = gEeprom.MrChannel[gEeprom.TX_CHANNEL];
#endif
break;
case MENU_SAVE:
gSubMenuSelection = gEeprom.BATTERY_SAVE;
break;
case MENU_VOX:
gSubMenuSelection = gEeprom.VOX_SWITCH ? gEeprom.VOX_LEVEL + 1 : 0;
break;
case MENU_ABR:
gSubMenuSelection = gEeprom.BACKLIGHT;
break;
case MENU_TDR:
gSubMenuSelection = gEeprom.DUAL_WATCH;
break;
case MENU_XB:
gSubMenuSelection = gEeprom.CROSS_BAND_RX_TX;
break;
case MENU_BEEP:
gSubMenuSelection = gEeprom.BEEP_CONTROL;
break;
case MENU_TOT:
gSubMenuSelection = gEeprom.TX_TIMEOUT_TIMER;
break;
#ifndef DISABLE_VOICE
case MENU_VOICE:
gSubMenuSelection = gEeprom.VOICE_PROMPT;
break;
#endif
case MENU_SC_REV:
gSubMenuSelection = gEeprom.SCAN_RESUME_MODE;
break;
case MENU_MDF:
gSubMenuSelection = gEeprom.CHANNEL_DISPLAY_MODE;
break;
case MENU_AUTOLK:
gSubMenuSelection = gEeprom.AUTO_KEYPAD_LOCK;
break;
case MENU_S_ADD1:
gSubMenuSelection = gTxVfo->SCANLIST1_PARTICIPATION;
break;
case MENU_S_ADD2:
gSubMenuSelection = gTxVfo->SCANLIST2_PARTICIPATION;
break;
case MENU_STE:
gSubMenuSelection = gEeprom.TAIL_NOTE_ELIMINATION;
break;
case MENU_RP_STE:
gSubMenuSelection = gEeprom.REPEATER_TAIL_TONE_ELIMINATION;
break;
case MENU_MIC:
gSubMenuSelection = gEeprom.MIC_SENSITIVITY;
break;
case MENU_1_CALL:
gSubMenuSelection = gEeprom.CHAN_1_CALL;
break;
case MENU_S_LIST:
gSubMenuSelection = gEeprom.SCAN_LIST_DEFAULT + 1;
break;
case MENU_SLIST1:
gSubMenuSelection = RADIO_FindNextChannel(0, 1, true, 0);
break;
case MENU_SLIST2:
gSubMenuSelection = RADIO_FindNextChannel(0, 1, true, 1);
break;
#ifndef DISABLE_ALARM
case MENU_AL_MOD:
gSubMenuSelection = gEeprom.ALARM_MODE;
break;
#endif
case MENU_D_ST:
gSubMenuSelection = gEeprom.DTMF_SIDE_TONE;
break;
case MENU_D_RSP:
gSubMenuSelection = gEeprom.DTMF_DECODE_RESPONSE;
break;
case MENU_D_HOLD:
gSubMenuSelection = gEeprom.DTMF_AUTO_RESET_TIME;
break;
case MENU_D_PRE:
gSubMenuSelection = gEeprom.DTMF_PRELOAD_TIME / 10;
break;
case MENU_PTT_ID:
gSubMenuSelection = gTxVfo->DTMF_PTT_ID_TX_MODE;
break;
case MENU_D_DCD:
gSubMenuSelection = gTxVfo->DTMF_DECODING_ENABLE;
break;
case MENU_D_LIST:
gSubMenuSelection = gDTMFChosenContact + 1;
break;
case MENU_PONMSG:
gSubMenuSelection = gEeprom.POWER_ON_DISPLAY_MODE;
break;
case MENU_ROGER:
gSubMenuSelection = gEeprom.ROGER;
break;
case MENU_AM:
gSubMenuSelection = gTxVfo->AM_CHANNEL_MODE;
break;
#ifndef DISABLE_NOAA
case MENU_NOAA_S:
gSubMenuSelection = gEeprom.NOAA_AUTO_SCAN;
break;
#endif
case MENU_DEL_CH:
#if 0
gSubMenuSelection = RADIO_FindNextChannel(gEeprom.MrChannel[0], 1, false, 1);
#else
gSubMenuSelection = RADIO_FindNextChannel(gEeprom.MrChannel[gEeprom.TX_CHANNEL], 1, false, 1);
#endif
break;
case MENU_350TX:
gSubMenuSelection = gSetting_350TX;
break;
case MENU_F_LOCK:
gSubMenuSelection = gSetting_F_LOCK;
break;
case MENU_200TX:
gSubMenuSelection = gSetting_200TX;
break;
case MENU_500TX:
gSubMenuSelection = gSetting_500TX;
break;
case MENU_350EN:
gSubMenuSelection = gSetting_350EN;
break;
case MENU_SCREN:
gSubMenuSelection = gSetting_ScrambleEnable;
break;
}
}
static void MENU_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
uint16_t Value = 0;
if (bKeyHeld)
return;
if (!bKeyPressed)
return;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_MENU;
if (!gIsInSubMenu)
{
switch (gInputBoxIndex)
{
case 1:
Value = gInputBox[0];
if (Value > 0 && Value <= gMenuListCount)
{
gMenuCursor = Value - 1;
gFlagRefreshSetting = true;
return;
}
break;
case 2:
gInputBoxIndex = 0;
Value = (gInputBox[0] * 10) + gInputBox[1];
if (Value > 0 && Value <= gMenuListCount)
{
gMenuCursor = Value - 1;
gFlagRefreshSetting = true;
return;
}
break;
}
gInputBoxIndex = 0;
}
else
{
if (gMenuCursor == MENU_OFFSET)
{
uint32_t Frequency;
if (gInputBoxIndex < 6)
{
#ifndef DISABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
return;
}
gInputBoxIndex = 0;
NUMBER_Get(gInputBox, &Frequency);
Frequency += 75;
#ifndef DISABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gSubMenuSelection = FREQUENCY_FloorToStep(Frequency, gTxVfo->StepFrequency, 0);
return;
}
if (gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH || gMenuCursor == MENU_1_CALL)
{
if (gInputBoxIndex < 3)
{
#ifndef DISABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
gInputBoxIndex = 0;
Value = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (IS_MR_CHANNEL(Value))
{
#ifndef DISABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gSubMenuSelection = Value;
return;
}
}
else
{
uint8_t Min;
uint8_t Max;
if (!MENU_GetLimits(gMenuCursor, &Min, &Max))
{
const uint8_t Offset = (Max >= 100) ? 3 : (Max >= 10) ? 2 : 1;
switch (gInputBoxIndex)
{
case 1:
Value = gInputBox[0];
break;
case 2:
Value = (gInputBox[0] * 10) + gInputBox[1];
break;
case 3:
Value = (gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2];
break;
}
if (Offset == gInputBoxIndex)
gInputBoxIndex = 0;
if (Value <= Max)
{
gSubMenuSelection = Value;
return;
}
}
else
gInputBoxIndex = 0;
}
}
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
static void MENU_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gCssScanMode == CSS_SCAN_MODE_OFF)
{
if (gIsInSubMenu)
{
if (gInputBoxIndex == 0 || gMenuCursor != MENU_OFFSET)
{
gAskForConfirmation = 0; // fix bug
gIsInSubMenu = false;
gInputBoxIndex = 0;
gFlagRefreshSetting = true;
#ifndef DISABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
}
else
gInputBox[--gInputBoxIndex] = 10;
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
#ifndef DISABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
}
else
{
MENU_StopCssScan();
#ifndef DISABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
gRequestDisplayScreen = DISPLAY_MENU;
}
gPttWasReleased = true;
}
}
static void MENU_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gRequestDisplayScreen = DISPLAY_MENU;
if (!gIsInSubMenu)
{
#ifndef DISABLE_VOICE
if (gMenuCursor != MENU_SCR)
gAnotherVoiceID = MenuVoices[gMenuCursor];
#endif
gAskForConfirmation = 0;
gIsInSubMenu = true;
}
else
{
if (gMenuCursor == MENU_RESET || gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH)
{
switch (gAskForConfirmation)
{
case 0:
gAskForConfirmation = 1;
break;
case 1:
gAskForConfirmation = 2;
UI_DisplayMenu();
if (gMenuCursor == MENU_RESET)
{
#ifndef DISABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_CONFIRM);
AUDIO_PlaySingleVoice(true);
#endif
MENU_AcceptSetting();
overlay_FLASH_RebootToBootloader();
}
gFlagAcceptSetting = true;
gIsInSubMenu = false;
gAskForConfirmation = 0;
}
}
else
{
gFlagAcceptSetting = true;
gIsInSubMenu = false;
}
gCssScanMode = CSS_SCAN_MODE_OFF;
#ifndef DISABLE_VOICE
if (gMenuCursor == MENU_SCR)
gAnotherVoiceID = (gSubMenuSelection == 0) ? VOICE_ID_SCRAMBLER_OFF : VOICE_ID_SCRAMBLER_ON;
else
gAnotherVoiceID = VOICE_ID_CONFIRM;
#endif
}
gInputBoxIndex = 0;
}
}
static void MENU_Key_STAR(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
RADIO_SelectVfos();
#ifndef DISABLE_NOAA
if (IS_NOT_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) && !gRxVfo->IsAM)
#else
if (!gRxVfo->IsAM)
#endif
{
if (gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_R_DCS)
{
if (gCssScanMode == CSS_SCAN_MODE_OFF)
{
MENU_StartCssScan(1);
gRequestDisplayScreen = DISPLAY_MENU;
#ifndef DISABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_SCANNING_BEGIN);
AUDIO_PlaySingleVoice(1);
#endif
}
else
{
MENU_StopCssScan();
gRequestDisplayScreen = DISPLAY_MENU;
#ifndef DISABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
}
gPttWasReleased = true;
return;
}
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
}
static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
{
uint8_t VFO;
uint8_t Channel;
bool bCheckScanList;
if (!bKeyHeld)
{
if (!bKeyPressed)
return;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gInputBoxIndex = 0;
}
else
if (!bKeyPressed)
return;
if (gCssScanMode != CSS_SCAN_MODE_OFF)
{
MENU_StartCssScan(Direction);
gPttWasReleased = true;
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
if (!gIsInSubMenu)
{
gMenuCursor = NUMBER_AddWithWraparound(gMenuCursor, -Direction, 0, gMenuListCount - 1);
gFlagRefreshSetting = true;
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
if (gMenuCursor == MENU_OFFSET)
{
int32_t Offset = (Direction * gTxVfo->StepFrequency) + gSubMenuSelection;
if (Offset < 99999990)
{
if (Offset < 0)
Offset = 99999990;
}
else
Offset = 0;
gSubMenuSelection = FREQUENCY_FloorToStep(Offset, gTxVfo->StepFrequency, 0);
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
VFO = 0;
switch (gMenuCursor)
{
case MENU_DEL_CH:
case MENU_1_CALL:
bCheckScanList = false;
break;
case MENU_SLIST2:
VFO = 1;
// Fallthrough
case MENU_SLIST1:
bCheckScanList = true;
break;
default:
MENU_ClampSelection(Direction);
gRequestDisplayScreen = DISPLAY_MENU;
return;
}
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
if (Channel != 0xFF)
gSubMenuSelection = Channel;
gRequestDisplayScreen = DISPLAY_MENU;
}
void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
switch (Key)
{
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
MENU_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:
MENU_Key_MENU(bKeyPressed, bKeyHeld);
break;
case KEY_UP:
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
break;
case KEY_DOWN:
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
break;
case KEY_EXIT:
MENU_Key_EXIT(bKeyPressed, bKeyHeld);
break;
case KEY_STAR:
MENU_Key_STAR(bKeyPressed, bKeyHeld);
break;
case KEY_F:
GENERIC_Key_F(bKeyPressed, bKeyHeld);
break;
case KEY_PTT:
GENERIC_Key_PTT(bKeyPressed);
break;
default:
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
if (gScreenToDisplay == DISPLAY_MENU && gMenuCursor == MENU_VOL)
gVoltageMenuCountdown = g_menu_timeout;
}