From 686c980637ef34172beb6fa60cdbb3288cd83cd3 Mon Sep 17 00:00:00 2001 From: manu Date: Mon, 25 Sep 2023 17:51:38 +0200 Subject: [PATCH] new menu --- CMakeLists.txt | 5 +- app/CMakeLists.txt | 3 +- app/app.c | 3 +- app/generic.c | 2 +- app/menu_new.c | 1190 ++++++++++++++++++++++++++++++++++++++++++++ app/menu_new.h | 34 ++ app/spectrum.c | 15 +- app/uart.c | 2 +- app/userapps.c | 18 +- helper/battery.c | 2 +- helper/boot.c | 2 +- ui/CMakeLists.txt | 3 +- ui/menu.c | 13 +- ui/menu_new.c | 553 ++++++++++++++++++++ ui/menu_new.h | 104 ++++ ui/spectrum.c | 48 +- ui/spectrum.h | 3 +- ui/ui.c | 2 +- 18 files changed, 1939 insertions(+), 63 deletions(-) create mode 100644 app/menu_new.c create mode 100644 app/menu_new.h create mode 100644 ui/menu_new.c create mode 100644 ui/menu_new.h diff --git a/CMakeLists.txt b/CMakeLists.txt index daabae32..55a17bd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,10 +80,9 @@ set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) set(CMAKE_AR arm-none-eabi-ar) set(CMAKE_OBJCOPY arm-none-eabi-objcopy) set(CMAKE_OBJDUMP arm-none-eabi-objdump) -set(SIZE arm-none-eabi-size) +set(CMAKE_SIZE_UTIL arm-none-eabi-size) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) -message(${CMAKE_C_COMPILER}) # project settings project(firmware ASM C) @@ -170,7 +169,7 @@ set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex) set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin) add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD - COMMAND ${SIZE} $ + COMMAND ${CMAKE_SIZE_UTIL} $ COMMAND ${CMAKE_OBJCOPY} -Oihex $ ${HEX_FILE} COMMAND ${CMAKE_OBJCOPY} -Obinary $ ${BIN_FILE} COMMAND python3 ${CMAKE_SOURCE_DIR}/fw-pack.py ${BIN_FILE} ${GIT_HASH} ${PROJECT_NAME}.packed.bin diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5d397ca3..adf64759 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -26,7 +26,8 @@ target_sources(firmware.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/dtmf.c ${CMAKE_CURRENT_SOURCE_DIR}/generic.c ${CMAKE_CURRENT_SOURCE_DIR}/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/menu.c + # ${CMAKE_CURRENT_SOURCE_DIR}/menu.c + ${CMAKE_CURRENT_SOURCE_DIR}/menu_new.c ${CMAKE_CURRENT_SOURCE_DIR}/scanner.c ${CMAKE_CURRENT_SOURCE_DIR}/spectrum.c ${CMAKE_CURRENT_SOURCE_DIR}/userapps.c diff --git a/app/app.c b/app/app.c index 6bd889f0..4b70842c 100644 --- a/app/app.c +++ b/app/app.c @@ -26,7 +26,7 @@ #endif #include "app/generic.h" #include "app/main.h" -#include "app/menu.h" +#include "app/menu_new.h" #include "app/scanner.h" #if defined(ENABLE_UART) #include "app/uart.h" @@ -57,7 +57,6 @@ #endif #include "ui/battery.h" #include "ui/inputbox.h" -#include "ui/menu.h" #include "ui/rssi.h" #include "ui/status.h" #include "ui/ui.h" diff --git a/app/generic.c b/app/generic.c index 2fee3940..b13bf124 100644 --- a/app/generic.c +++ b/app/generic.c @@ -19,7 +19,7 @@ #include "app/fm.h" #endif #include "app/generic.h" -#include "app/menu.h" +#include "app/menu_new.h" #include "app/scanner.h" #include "audio.h" #include "driver/keyboard.h" diff --git a/app/menu_new.c b/app/menu_new.c new file mode 100644 index 00000000..3f320c5e --- /dev/null +++ b/app/menu_new.c @@ -0,0 +1,1190 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * Copyright 2023 Manuel Jedinger + * https://github.com/manujedi + * + * 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 +#if !defined(ENABLE_OVERLAY) +#include "ARMCM0.h" +#endif +#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" +#if defined(ENABLE_OVERLAY) +#include "sram-overlay.h" +#endif +#include "ui/inputbox.h" +#include "ui/ui.h" +#include "ui/menu_new.h" + +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, + VOICE_ID_VOICE_PROMPT, + 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, + 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, + VOICE_ID_INVALID, + 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, +}; + +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_TXP: case MENU_SFT_D: + case MENU_TDR: case MENU_WX: + case MENU_VOICE: case MENU_SC_REV: + case MENU_MDF: 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: +#if defined(ENABLE_ALARM) + case MENU_AL_MOD: +#endif + case MENU_D_ST: case MENU_D_DCD: + case MENU_AM: +#if defined(ENABLE_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, 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 = 1; + return; + } + gSubMenuSelection = gTxVfo->STEP_SETTING; + return; + + case MENU_TXP: + gTxVfo->OUTPUT_POWER = gSubMenuSelection; + gRequestSaveChannel = 1; + 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 = 1; + return; + + case MENU_SCR: + gTxVfo->SCRAMBLING_TYPE = gSubMenuSelection; + gRequestSaveChannel = 1; + return; + + case MENU_BCL: + gTxVfo->BUSY_CHANNEL_LOCK = gSubMenuSelection; + gRequestSaveChannel = 1; + 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_WX: + if (IS_NOAA_CHANNEL(gEeprom.ScreenChannel[0])) { + return; + } + if (IS_NOAA_CHANNEL(gEeprom.ScreenChannel[1])) { + return; + } + 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; + + case MENU_VOICE: + gEeprom.VOICE_PROMPT = gSubMenuSelection; + gRequestSaveSettings = true; + gUpdateStatus = true; + return; + + 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 = 0x1e; + 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; + +#if defined(ENABLE_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 = 1; + return; + +#if defined(ENABLE_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); + + if (gSelectedCodeType == CODE_TYPE_CONTINUOUS_TONE) { + ScanPauseDelayIn10msec = 20; + } else { + ScanPauseDelayIn10msec = 30; + } + + gUpdateDisplay = true; +} + +static void MENU_ClampSelection(int8_t Direction) +{ + uint8_t Min, 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: + if (gTxVfo->ConfigRX.CodeType == CODE_TYPE_CONTINUOUS_TONE) { + gSubMenuSelection = gTxVfo->ConfigRX.Code + 1; + } else { + gSubMenuSelection = 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: + if (gTxVfo->ConfigTX.CodeType == CODE_TYPE_CONTINUOUS_TONE) { + gSubMenuSelection = gTxVfo->ConfigTX.Code + 1; + } else { + gSubMenuSelection = 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: + gSubMenuSelection = gEeprom.MrChannel[0]; + break; + + case MENU_SAVE: + gSubMenuSelection = gEeprom.BATTERY_SAVE; + break; + + case MENU_VOX: + if (gEeprom.VOX_SWITCH) { + gSubMenuSelection = gEeprom.VOX_LEVEL + 1; + } else { + gSubMenuSelection = 0; + } + break; + + case MENU_ABR: + gSubMenuSelection = gEeprom.BACKLIGHT; + break; + + case MENU_TDR: + gSubMenuSelection = gEeprom.DUAL_WATCH; + break; + + case MENU_WX: + gSubMenuSelection = gEeprom.CROSS_BAND_RX_TX; + break; + + case MENU_BEEP: + gSubMenuSelection = gEeprom.BEEP_CONTROL; + break; + + case MENU_TOT: + gSubMenuSelection = gEeprom.TX_TIMEOUT_TIMER; + break; + + case MENU_VOICE: + gSubMenuSelection = gEeprom.VOICE_PROMPT; + break; + + 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; + +#if defined(ENABLE_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; + +#if defined(ENABLE_NOAA) + case MENU_NOAA_S: + gSubMenuSelection = gEeprom.NOAA_AUTO_SCAN; + break; +#endif + + case MENU_DEL_CH: + gSubMenuSelection = RADIO_FindNextChannel(gEeprom.MrChannel[0], 1, false, 1); + 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 && Value <= gMenuListCount) { + gMenuCursor = Value - 1; + gFlagRefreshSetting = true; + return; + } + break; + case 2: + gInputBoxIndex = 0; + Value = (gInputBox[0] * 10) + gInputBox[1]; + if (Value && Value <= gMenuListCount) { + gMenuCursor = Value - 1; + gFlagRefreshSetting = true; + return; + } + break; + } + gInputBoxIndex = 0; + } else { + if (gMenuCursor == MENU_OFFSET) { + uint32_t Frequency; + + if (gInputBoxIndex < 6) { + gAnotherVoiceID = (VOICE_ID_t)Key; + return; + } + gInputBoxIndex = 0; + NUMBER_Get(gInputBox, &Frequency); + Frequency += 75; + gAnotherVoiceID = (VOICE_ID_t)Key; + gSubMenuSelection = FREQUENCY_FloorToStep(Frequency, gTxVfo->StepFrequency, 0); + return; + } + if (gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH || gMenuCursor == MENU_1_CALL) { + if (gInputBoxIndex < 3) { + gAnotherVoiceID = (VOICE_ID_t)Key; + gRequestDisplayScreen = DISPLAY_MENU; + return; + } + gInputBoxIndex = 0; + Value = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1; + if (IS_MR_CHANNEL(Value)) { + gAnotherVoiceID = (VOICE_ID_t)Key; + gSubMenuSelection = Value; + return; + } + } else { + uint8_t Min, Max; + + if (!MENU_GetLimits(gMenuCursor, &Min, &Max)) { + uint8_t Offset; + + if (Max < 100) { + if (Max < 10) { + Offset = 1; + } else { + Offset = 2; + } + } else { + Offset = 3; + } + 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) { + gIsInSubMenu = false; + gInputBoxIndex = 0; + gFlagRefreshSetting = true; + gAnotherVoiceID = VOICE_ID_CANCEL; + gAskForConfirmation = 0; + } else { + gInputBoxIndex--; + gInputBox[gInputBoxIndex] = 10; + } + gRequestDisplayScreen = DISPLAY_MENU; + return; + } + gAnotherVoiceID = VOICE_ID_CANCEL; + gRequestDisplayScreen = DISPLAY_MAIN; + } else { + MENU_StopCssScan(); + gAnotherVoiceID = VOICE_ID_SCANNING_STOP; + 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) { + if (gMenuCursor != MENU_SCR) { + gAnotherVoiceID = MenuVoices[gMenuCursor]; + } + 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) { + AUDIO_SetVoiceID(0, VOICE_ID_CONFIRM); + AUDIO_PlaySingleVoice(true); + MENU_AcceptSetting(); +#if defined(ENABLE_OVERLAY) + overlay_FLASH_RebootToBootloader(); +#else + NVIC_SystemReset(); +#endif + } + gFlagAcceptSetting = true; + gIsInSubMenu = false; + gAskForConfirmation = 0; + } + } else { + gFlagAcceptSetting = true; + gIsInSubMenu = false; + } + gCssScanMode = CSS_SCAN_MODE_OFF; + if (gMenuCursor == MENU_SCR) { + if (gSubMenuSelection == 0) { + gAnotherVoiceID = VOICE_ID_SCRAMBLER_OFF; + } else { + gAnotherVoiceID = VOICE_ID_SCRAMBLER_ON; + } + } else { + gAnotherVoiceID = VOICE_ID_CONFIRM; + } + } + gInputBoxIndex = 0; + } +} + +static void MENU_Key_STAR(bool bKeyPressed, bool bKeyHeld) +{ + if (!bKeyHeld && bKeyPressed) { + gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; + RADIO_SelectVfos(); + if (IS_NOT_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) && !gRxVfo->IsAM) { + if (gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_R_DCS) { + if (gCssScanMode == CSS_SCAN_MODE_OFF) { + MENU_StartCssScan(1); + gRequestDisplayScreen = DISPLAY_MENU; + AUDIO_SetVoiceID(0, VOICE_ID_SCANNING_BEGIN); + AUDIO_PlaySingleVoice(1); + } else { + MENU_StopCssScan(); + gRequestDisplayScreen = DISPLAY_MENU; + gAnotherVoiceID = VOICE_ID_SCANNING_STOP; + } + } + 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) { + gFlagRefreshSetting = true; + gRequestDisplayScreen = DISPLAY_MENU; + //end of tab (down) + if(Direction == -1) { + if (Tabs[gMenuTab][0] - 1 <= gInTabSelection) { + gMenuTab = NUMBER_AddWithWraparound(gMenuTab, +1, 0, sizeof (Tabs) / sizeof (Tabs[0]) - 1); + gInTabSelection = Tabs[gMenuTab][0] - 1; + gMenuCursor = Tabs[gMenuTab][gInTabSelection + 1]; + return; + } + } else { + //top of tab + if (gInTabSelection == 0) { + gMenuTab = NUMBER_AddWithWraparound(gMenuTab, -1, 0, sizeof (Tabs) / sizeof (Tabs[0]) - 1); + gInTabSelection = 0; + gMenuCursor = Tabs[gMenuTab][gInTabSelection + 1]; + return; + } + } + //needs to be inverted + gInTabSelection -= Direction; + gMenuCursor = Tabs[gMenuTab][gInTabSelection + 1]; + + return; + } + + if (gMenuCursor == MENU_OFFSET) { + int32_t Offset; + + 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 = 0x20; + } +} + diff --git a/app/menu_new.h b/app/menu_new.h new file mode 100644 index 00000000..76c14929 --- /dev/null +++ b/app/menu_new.h @@ -0,0 +1,34 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * Copyright 2023 Manuel Jedinger + * https://github.com/manujedi + * + * 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. + */ + +#ifndef APP_MENU_H +#define APP_MENU_H + +#include "driver/keyboard.h" + +int MENU_GetLimits(uint8_t Cursor, uint8_t *pMin, uint8_t *pMax); +void MENU_AcceptSetting(void); +void MENU_SelectNextCode(void); +void MENU_ShowCurrentSetting(void); +void MENU_StartCssScan(int8_t Direction); +void MENU_StopCssScan(void); + +void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld); + +#endif + diff --git a/app/spectrum.c b/app/spectrum.c index 824390e8..9589f982 100644 --- a/app/spectrum.c +++ b/app/spectrum.c @@ -41,7 +41,7 @@ uint32_t pow10(uint8_t exponent) { return ret; } -uint8_t log10(uint32_t val) { +uint8_t log10_internal(uint32_t val) { uint8_t ret = 0; val /= 10; while (val) { @@ -62,6 +62,9 @@ void spectrum_loop() { uint8_t rssi_val[56]; uint8_t i = 0; + //original negativ values + uint8_t rssi_min = 100; + uint8_t rssi_max = 50; memset(rssi_val, 0xFF, sizeof(rssi_val)); @@ -79,12 +82,14 @@ void spectrum_loop() { break; case KEY_1: if (FrequencyStep < 1000000) - FrequencyStep += pow10(log10(FrequencyStep)); + FrequencyStep += pow10(log10_internal(FrequencyStep)); updateUI = true; break; case KEY_2: + rssi_min += 1; break; case KEY_3: + rssi_max += 1; break; case KEY_4: break; @@ -94,12 +99,14 @@ void spectrum_loop() { break; case KEY_7: if (FrequencyStep > 1) - FrequencyStep -= pow10(log10(FrequencyStep)-1); + FrequencyStep -= pow10(log10_internal(FrequencyStep)-1); updateUI = true; break; case KEY_8: + rssi_min -= 1; break; case KEY_9: + rssi_max -= 1; break; case KEY_UP: Frequency -= FrequencyStep; @@ -132,7 +139,7 @@ void spectrum_loop() { i++; if (i >= 56) { i = 0; - spectrum_drawSpectrum(rssi_val, Frequency, FrequencyStep); + spectrum_drawSpectrum(rssi_val, Frequency, FrequencyStep, rssi_min, rssi_max); } if (updateUI) { diff --git a/app/uart.c b/app/uart.c index b934861f..e6eb18b0 100644 --- a/app/uart.c +++ b/app/uart.c @@ -91,7 +91,7 @@ typedef struct { uint8_t Size; bool bAllowPassword; uint32_t Timestamp; - uint8_t Data[0]; + uint8_t* Data; } CMD_051D_t; typedef struct { diff --git a/app/userapps.c b/app/userapps.c index 17817ab2..69d56228 100644 --- a/app/userapps.c +++ b/app/userapps.c @@ -131,8 +131,6 @@ void USERAPPS_loop(void){ key = USERAPPS_GetInput(); switch (key) { - case KEY_0 ... KEY_9: - break; case KEY_UP: selection = selection == 0 ? 0 : selection - 1; break; @@ -140,23 +138,11 @@ void USERAPPS_loop(void){ if(selection < sizeof(menu_items)/sizeof(menu_items[0]) - 1) selection++; break; - case KEY_EXIT: - break; - case KEY_STAR: - break; - case KEY_F: - break; - case KEY_PTT: - break; - case KEY_SIDE2: - break; - case KEY_SIDE1: - break; - case KEY_INVALID: - break; case KEY_MENU: USERAPPS_startapp(selection); break; + default: + break; } USERAPPS_draw(selection); diff --git a/helper/battery.c b/helper/battery.c index b88f1889..cfde1813 100644 --- a/helper/battery.c +++ b/helper/battery.c @@ -18,7 +18,7 @@ #include "driver/backlight.h" #include "misc.h" #include "ui/battery.h" -#include "ui/menu.h" +#include "ui/menu_new.h" #include "ui/ui.h" uint16_t gBatteryCalibration[6]; diff --git a/helper/boot.c b/helper/boot.c index bbe2d366..604ebd32 100644 --- a/helper/boot.c +++ b/helper/boot.c @@ -24,7 +24,7 @@ #include "misc.h" #include "radio.h" #include "settings.h" -#include "ui/menu.h" +#include "ui/menu_new.h" #include "ui/ui.h" BOOT_Mode_t BOOT_GetMode(void) diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 1ba31e3e..afb524c9 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -20,7 +20,8 @@ target_sources(firmware.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inputbox.c ${CMAKE_CURRENT_SOURCE_DIR}/lock.c ${CMAKE_CURRENT_SOURCE_DIR}/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/menu.c + # ${CMAKE_CURRENT_SOURCE_DIR}/menu.c + ${CMAKE_CURRENT_SOURCE_DIR}/menu_new.c ${CMAKE_CURRENT_SOURCE_DIR}/rssi.c ${CMAKE_CURRENT_SOURCE_DIR}/scanner.c ${CMAKE_CURRENT_SOURCE_DIR}/status.c diff --git a/ui/menu.c b/ui/menu.c index 5a65211f..4dd46056 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -25,7 +25,7 @@ #include "settings.h" #include "ui/helper.h" #include "ui/inputbox.h" -#include "ui/menu.h" +#include "ui/menu_new.h" #include "ui/ui.h" static const char MenuList[][7] = { @@ -186,22 +186,21 @@ void UI_DisplayMenu(void) memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - for (i = 0; i < 6; i++) { + for (i = 0; i < 5; i++) { if ((gMenuCursor + i) < (gMenuListCount)) { - UI_PrintStringSmall(MenuList[gMenuCursor + i], 0, 127, i, 8, false); + UI_PrintStringSmall(MenuList[gMenuCursor + i], 0, 127, i+1, 8, false); } } for (i = 0; i < 48; i++) { - gFrameBuffer[0][i] ^= 0xFF; + gFrameBuffer[1][i] ^= 0xFF; } - for (i = 0; i < 7; i++) { + for (i = 1; i < 7; i++) { gFrameBuffer[i][48] = 0xFF; - gFrameBuffer[i][49] = 0xFF; } NUMBER_ToDigits(gMenuCursor + 1, String); UI_DisplaySmallDigits(2, String + 6, 33, 6); if (gIsInSubMenu) { - memcpy(gFrameBuffer[0] + 50, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator)); + memcpy(gFrameBuffer[1] + 50, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator)); } memset(String, 0, sizeof(String)); diff --git a/ui/menu_new.c b/ui/menu_new.c new file mode 100644 index 00000000..3d909d5d --- /dev/null +++ b/ui/menu_new.c @@ -0,0 +1,553 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * Copyright 2023 Manuel Jedinger + * https://github.com/manujedi + * + * 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 +#include "app/dtmf.h" +#include "bitmaps.h" +#include "dcs.h" +#include "driver/st7565.h" +#include "external/printf/printf.h" +#include "helper/battery.h" +#include "misc.h" +#include "settings.h" +#include "ui/helper.h" +#include "ui/inputbox.h" +#include "ui/menu_new.h" +#include "ui/ui.h" + + +static const char MenuList[][7] = { + // 0x00 + "SQL", "STEP", "TXP", "R_DCS", + "R_CTCS", "T_DCS", "T_CTCS", "SFT-D", + // 0x08 + "OFFSET", "W/N", "SCR", "BCL", + "MEM-CH", "SAVE", "VOX", "ABR", + // 0x10 + "TDR", "WX", "BEEP", "TOT", + "VOICE", "SC-REV", "MDF", "AUTOLK", + // 0x18 + "S-ADD1", "S-ADD2", "STE", "RP-STE", + "MIC", "1-CALL", "S-LIST", "SLIST1", + // 0x20 + "SLIST2", +#if defined(ENABLE_ALARM) + "AL-MOD", +#endif + "ANI-ID", "UPCODE", + "DWCODE", "D-ST", "D-RSP", "D-HOLD", + // 0x28 + "D-PRE", "PTT-ID", "D-DCD", "D-LIST", + "PONMSG", "ROGER", "VOL", "AM", + // 0x30 +#if defined(ENABLE_NOAA) + "NOAA_S", +#endif + "DEL-CH", "RESET", "350TX", + "F-LOCK", "200TX", "500TX", "350EN", + // 0x38 + "SCREN", +}; + +static const uint16_t gSubMenu_Step[] = { + 250, + 500, + 625, + 1000, + 1250, + 2500, + 833, +}; + +static const char gSubMenu_TXP[3][5] = { + "LOW", + "MID", + "HIGH", +}; + +static const char gSubMenu_SFT_D[3][4] = { + "OFF", + "+", + "-", +}; + +static const char gSubMenu_W_N[2][7] = { + "WIDE", + "NARROW", +}; + +static const char gSubMenu_OFF_ON[2][4] = { + "OFF", + "ON", +}; + +static const char gSubMenu_SAVE[5][4] = { + "OFF", + "1:1", + "1:2", + "1:3", + "1:4", +}; + +static const char gSubMenu_CHAN[3][7] = { + "OFF", + "CHAN_A", + "CHAN_B", +}; + +static const char gSubMenu_VOICE[3][4] = { + "OFF", + "CHI", + "ENG", +}; + +static const char gSubMenu_SC_REV[3][3] = { + "TO", + "CO", + "SE", +}; + +static const char gSubMenu_MDF[3][5] = { + "FREQ", + "CHAN", + "NAME", +}; + +#if defined(ENABLE_ALARM) +static const char gSubMenu_AL_MOD[2][5] = { + "SITE", + "TONE", +}; +#endif + +static const char gSubMenu_D_RSP[4][6] = { + "NULL", + "RING", + "REPLY", + "BOTH", +}; + +static const char gSubMenu_PTT_ID[4][5] = { + "OFF", + "BOT", + "EOT", + "BOTH", +}; + +static const char gSubMenu_PONMSG[3][5] = { + "FULL", + "MSG", + "VOL", +}; + +static const char gSubMenu_ROGER[3][6] = { + "OFF", + "ROGER", + "MDC", +}; + +static const char gSubMenu_RESET[2][4] = { + "VFO", + "ALL", +}; + +static const char gSubMenu_F_LOCK[6][4] = { + "OFF", + "FCC", + "CE", + "GB", + "430", + "438", +}; + +static const char gMenuTabNames[8][12] = { + "RADIO", + "RX", + "TX", + "MEM", + "SYS", + "DISP", + "DTMF", + "USELESS", +}; + +const uint8_t Tabs[8][11] = { + {8, MENU_SQL, MENU_STEP, MENU_TXP, MENU_OFFSET, MENU_SFT_D, MENU_W_N, MENU_BCL, MENU_AM}, + {6, MENU_R_DCS, MENU_R_CTCS, MENU_STE, MENU_RP_STE, MENU_NOAA_S, MENU_SC_REV}, + {3, MENU_T_DCS, MENU_T_CTCS, MENU_ROGER}, + {9, MENU_MEM_CH, MENU_S_ADD1, MENU_S_ADD2, MENU_1_CALL, MENU_S_LIST, MENU_SLIST1, MENU_SLIST2, MENU_DEL_CH, MENU_RESET}, + {8, MENU_SAVE, MENU_VOX, MENU_ABR, MENU_TDR, MENU_WX, MENU_TOT, MENU_MIC, MENU_VOL}, + {3, MENU_MDF, MENU_AUTOLK,MENU_PONMSG}, + {10, MENU_ANI_ID, MENU_UPCODE, MENU_DWCODE, MENU_D_ST, MENU_D_RSP, MENU_D_HOLD, MENU_D_PRE, MENU_PTT_ID,MENU_D_DCD, MENU_D_LIST}, + {4, MENU_SCR, MENU_BEEP, MENU_VOICE, MENU_AL_MOD}, +}; + + +bool gIsInSubMenu; + +uint8_t gMenuTab; +uint8_t gInTabSelection; +uint8_t gMenuCursor; +int8_t gMenuScrollDirection; +uint32_t gSubMenuSelection; + +void UI_DisplayMenu(void) { + + char String[16]; + char Contact[16]; + uint8_t i; + uint8_t lineLength; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + + i = 0; + lineLength = 1; + do { + if (i >= sizeof(gMenuTabNames) / sizeof(gMenuTabNames[0])) + break; + + uint8_t len = strlen(gMenuTabNames[gMenuTab + i]) * 7; + if ((lineLength+len) > 100) + break; + + UI_PrintStringSmall(gMenuTabNames[gMenuTab + i], lineLength, 127, 0, 7, false); + lineLength += len; + + if (!i) { + for (int j = 0; j < lineLength+2; ++j) { + gFrameBuffer[0][j] ^= 0xFF; + } + } + + gFrameBuffer[0][lineLength + 2] = 0xFF; + lineLength += 5; + i++; + } while (1); + + for (i = 0; i < 6; i++) { + if (gInTabSelection + i < Tabs[gMenuTab][0]) { + UI_PrintStringSmall(MenuList[Tabs[gMenuTab][gInTabSelection + i + 1]], 0, 127, i + 1, 7, false); + } + } + + for (i = 0; i < 48; i++) { + gFrameBuffer[1][i] ^= 0xFF; + } + + for (i = 1; i < 7; i++) { + gFrameBuffer[i][48] = 0xFF; + } + + if (gIsInSubMenu) { + memcpy(gFrameBuffer[1] + 50, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator)); + } + + memset(String, 0, sizeof(String)); + memset(Contact, 0, sizeof(String)); + + + switch (gMenuCursor) { + case MENU_SQL: + case MENU_MIC: + sprintf(String, "%d", gSubMenuSelection); + break; + + case MENU_STEP: + sprintf(String, "%d.%02dKHz", gSubMenu_Step[gSubMenuSelection] / 100, + gSubMenu_Step[gSubMenuSelection] % 100); + break; + + case MENU_TXP: + strcpy(String, gSubMenu_TXP[gSubMenuSelection]); + break; + + case MENU_R_DCS: + case MENU_T_DCS: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else if (gSubMenuSelection < 105) { + sprintf(String, "D%03oN", DCS_Options[gSubMenuSelection - 1]); + } else { + sprintf(String, "D%03oI", DCS_Options[gSubMenuSelection - 105]); + } + break; + + case MENU_R_CTCS: + case MENU_T_CTCS: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%d.%dHz", CTCSS_Options[gSubMenuSelection - 1] / 10, + CTCSS_Options[gSubMenuSelection - 1] % 10); + } + break; + + case MENU_SFT_D: + strcpy(String, gSubMenu_SFT_D[gSubMenuSelection]); + break; + + case MENU_OFFSET: + if (!gIsInSubMenu || gInputBoxIndex == 0) { + sprintf(String, "%d.%05d", gSubMenuSelection / 100000, gSubMenuSelection % 100000); + break; + } + for (i = 0; i < 3; i++) { + if (gInputBox[i] == 10) { + String[i] = '-'; + } else { + String[i] = gInputBox[i] + '0'; + } + } + String[3] = '.'; + for (i = 3; i < 6; i++) { + if (gInputBox[i] == 10) { + String[i + 1] = '-'; + } else { + String[i + 1] = gInputBox[i] + '0'; + } + } + String[7] = '-'; + String[8] = '-'; + String[9] = 0; + String[10] = 0; + String[11] = 0; + break; + + case MENU_W_N: + strcpy(String, gSubMenu_W_N[gSubMenuSelection]); + break; + + case MENU_SCR: + case MENU_VOX: + case MENU_ABR: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%d", gSubMenuSelection); + } + break; + + case MENU_BCL: + case MENU_BEEP: + case MENU_AUTOLK: + case MENU_S_ADD1: + case MENU_S_ADD2: + case MENU_STE: + case MENU_D_ST: + case MENU_D_DCD: + case MENU_AM: +#if defined(ENABLE_NOAA) + case MENU_NOAA_S: +#endif + case MENU_350TX: + case MENU_200TX: + case MENU_500TX: + case MENU_350EN: + case MENU_SCREN: + strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]); + break; + + case MENU_MEM_CH: + case MENU_1_CALL: + case MENU_DEL_CH: + UI_GenerateChannelStringEx( + String, + RADIO_CheckValidChannel((uint16_t) gSubMenuSelection, false, 0), + (uint8_t) gSubMenuSelection + ); + break; + + case MENU_SAVE: + strcpy(String, gSubMenu_SAVE[gSubMenuSelection]); + break; + + case MENU_TDR: + case MENU_WX: + strcpy(String, gSubMenu_CHAN[gSubMenuSelection]); + break; + + case MENU_TOT: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%dmin", gSubMenuSelection); + } + break; + + case MENU_VOICE: + strcpy(String, gSubMenu_VOICE[gSubMenuSelection]); + break; + + case MENU_SC_REV: + strcpy(String, gSubMenu_SC_REV[gSubMenuSelection]); + break; + + case MENU_MDF: + strcpy(String, gSubMenu_MDF[gSubMenuSelection]); + break; + + case MENU_RP_STE: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%d*100ms", gSubMenuSelection); + } + break; + + case MENU_S_LIST: + sprintf(String, "LIST%d", gSubMenuSelection); + break; + +#if defined(ENABLE_ALARM) + case MENU_AL_MOD: + sprintf(String, gSubMenu_AL_MOD[gSubMenuSelection]); + break; +#endif + + case MENU_ANI_ID: + strcpy(String, gEeprom.ANI_DTMF_ID); + break; + + case MENU_UPCODE: + strcpy(String, gEeprom.DTMF_UP_CODE); + break; + + case MENU_DWCODE: + strcpy(String, gEeprom.DTMF_DOWN_CODE); + break; + + case MENU_D_RSP: + strcpy(String, gSubMenu_D_RSP[gSubMenuSelection]); + break; + + case MENU_D_HOLD: + sprintf(String, "%ds", gSubMenuSelection); + break; + + case MENU_D_PRE: + sprintf(String, "%d*10ms", gSubMenuSelection); + break; + + case MENU_PTT_ID: + strcpy(String, gSubMenu_PTT_ID[gSubMenuSelection]); + break; + + case MENU_D_LIST: + gIsDtmfContactValid = DTMF_GetContact((uint8_t) gSubMenuSelection - 1, Contact); + if (!gIsDtmfContactValid) { + // Ghidra being weird again... + memcpy(String, "NULL\0\0\0", 8); + } else { + memcpy(String, Contact, 8); + } + break; + + case MENU_PONMSG: + strcpy(String, gSubMenu_PONMSG[gSubMenuSelection]); + break; + + case MENU_ROGER: + strcpy(String, gSubMenu_ROGER[gSubMenuSelection]); + break; + + case MENU_VOL: + sprintf(String, "%d.%02dV", gBatteryVoltageAverage / 100, gBatteryVoltageAverage % 100); + break; + + case MENU_RESET: + strcpy(String, gSubMenu_RESET[gSubMenuSelection]); + break; + + case MENU_F_LOCK: + strcpy(String, gSubMenu_F_LOCK[gSubMenuSelection]); + break; + } + + UI_PrintStringSmall(String, 50, 127, 2, 8, true); + + if (gMenuCursor == MENU_OFFSET) { + UI_PrintStringSmall("MHz", 50, 127, 4, 8, true); + } + + if ((gMenuCursor == MENU_RESET || gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH) && + gAskForConfirmation) { + if (gAskForConfirmation == 1) { + strcpy(String, "SURE?"); + } else { + strcpy(String, "WAIT!"); + } + UI_PrintStringSmall(String, 50, 127, 4, 8, true); + } + + if ((gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_R_DCS) && gCssScanMode != CSS_SCAN_MODE_OFF) { + UI_PrintStringSmall("SCAN", 50, 127, 4, 8, true); + } + + if (gMenuCursor == MENU_UPCODE) { + if (strlen(gEeprom.DTMF_UP_CODE) > 8) { + UI_PrintStringSmall(gEeprom.DTMF_UP_CODE + 8, 50, 127, 4, 8, true); + } + } + if (gMenuCursor == MENU_DWCODE) { + if (strlen(gEeprom.DTMF_DOWN_CODE) > 8) { + UI_PrintStringSmall(gEeprom.DTMF_DOWN_CODE + 8, 50, 127, 4, 8, true); + } + } + if (gMenuCursor == MENU_D_LIST && gIsDtmfContactValid) { + Contact[11] = 0; + memcpy(&gDTMF_ID, Contact + 8, 4); + sprintf(String, "ID:%s", Contact + 8); + UI_PrintStringSmall(String, 50, 127, 4, 8, true); + } + + if (gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_T_CTCS || + gMenuCursor == MENU_R_DCS || gMenuCursor == MENU_T_DCS || gMenuCursor == MENU_D_LIST) { + uint8_t Offset; + + NUMBER_ToDigits((uint8_t) gSubMenuSelection, String); + Offset = (gMenuCursor == MENU_D_LIST) ? 2 : 3; + UI_DisplaySmallDigits(Offset, String + (8 - Offset), 105, 0); + } + + if (gMenuCursor == MENU_SLIST1 || gMenuCursor == MENU_SLIST2) { + i = gMenuCursor - MENU_SLIST1; + + if (gSubMenuSelection == 0xFF) { + sprintf(String, "NULL"); + } else { + UI_GenerateChannelStringEx(String, true, (uint8_t) gSubMenuSelection); + } + + if (gSubMenuSelection == 0xFF || !gEeprom.SCAN_LIST_ENABLED[i]) { + UI_PrintStringSmall(String, 50, 127, 2, 8, 1); + } else { + UI_PrintStringSmall(String, 50, 127, 0, 8, 1); + if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH1[i])) { + sprintf(String, "PRI1:%d", gEeprom.SCANLIST_PRIORITY_CH1[i] + 1); + UI_PrintStringSmall(String, 50, 127, 2, 8, 1); + } + if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH2[i])) { + sprintf(String, "PRI2:%d", gEeprom.SCANLIST_PRIORITY_CH2[i] + 1); + UI_PrintStringSmall(String, 50, 127, 4, 8, 1); + } + } + } + + ST7565_BlitFullScreen(); +} + diff --git a/ui/menu_new.h b/ui/menu_new.h new file mode 100644 index 00000000..842ea42e --- /dev/null +++ b/ui/menu_new.h @@ -0,0 +1,104 @@ +/* Copyright 2023 Dual Tachyon + * https://github.com/DualTachyon + * Copyright 2023 Manuel Jedinger + * https://github.com/manujedi + * + * 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. + */ + +#ifndef UI_MENU_H +#define UI_MENU_H + +#include +#include + +enum { + MENU_SQL = 0, + MENU_STEP, + MENU_TXP, + MENU_R_DCS, + MENU_R_CTCS, + MENU_T_DCS, + MENU_T_CTCS, + MENU_SFT_D, + MENU_OFFSET, + MENU_W_N, + MENU_SCR, + MENU_BCL, + MENU_MEM_CH, + MENU_SAVE, + MENU_VOX, + MENU_ABR, + MENU_TDR, + MENU_WX, + MENU_BEEP, + MENU_TOT, + MENU_VOICE, + MENU_SC_REV, + MENU_MDF, + MENU_AUTOLK, + MENU_S_ADD1, + MENU_S_ADD2, + MENU_STE, + MENU_RP_STE, + MENU_MIC, + MENU_1_CALL, + MENU_S_LIST, + MENU_SLIST1, + MENU_SLIST2, +#if defined(ENABLE_ALARM) + MENU_AL_MOD, +#endif + MENU_ANI_ID, + MENU_UPCODE, + MENU_DWCODE, + MENU_D_ST, + MENU_D_RSP, + MENU_D_HOLD, + MENU_D_PRE, + MENU_PTT_ID, + MENU_D_DCD, + MENU_D_LIST, + MENU_PONMSG, + MENU_ROGER, + MENU_VOL, + MENU_AM, +#if defined(ENABLE_NOAA) + MENU_NOAA_S, +#endif + MENU_DEL_CH, + MENU_RESET, + MENU_350TX, + MENU_F_LOCK, + MENU_200TX, + MENU_500TX, + MENU_350EN, + MENU_SCREN, +}; + + + +extern bool gIsInSubMenu; + +extern uint8_t gMenuTab; +extern uint8_t gInTabSelection; +extern uint8_t gMenuCursor; +extern int8_t gMenuScrollDirection; +extern uint32_t gSubMenuSelection; + +extern const uint8_t Tabs[8][11]; + +void UI_DisplayMenu(void); + +#endif + diff --git a/ui/spectrum.c b/ui/spectrum.c index f08da735..21b5fe23 100644 --- a/ui/spectrum.c +++ b/ui/spectrum.c @@ -49,20 +49,30 @@ void spectrum_drawUI(uint32_t Frequency, uint32_t FrequencyStep) { ST7565_BlitStatusLine(); } -void spectrum_drawSpectrum(uint8_t rssi_val[56], uint32_t Frequency, uint32_t FrequencyStep) { +void spectrum_drawSpectrum(uint8_t rssi_val[56], uint32_t Frequency, uint32_t FrequencyStep, uint8_t min, uint8_t max) { memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - uint8_t max = 0; - uint8_t min = -1; - uint8_t max_index = -1; + uint8_t line; + uint8_t bit; + uint8_t tmp; + uint8_t max_index = 0; + uint8_t max_measurement = 0xFF; + uint8_t diff = max - min; for (uint8_t i = 0; i < 56; ++i) { - if (rssi_val[i] > max) - max = rssi_val[i]; - if (rssi_val[i] < min) { - min = rssi_val[i]; - max_index = i; //rssi is negativ + line = i / 8; + bit = i % 8; + + tmp = max - rssi_val[i]; + tmp = (50 * tmp) / diff; + for (uint8_t j = 0; j < tmp; ++j) { + gFrameBuffer[line][j] |= (1 << bit); + } + if(max_measurement < rssi_val[i]){ + max_measurement = rssi_val[i]; + max_index = i; } + } char String[16]; @@ -71,26 +81,18 @@ void spectrum_drawSpectrum(uint8_t rssi_val[56], uint32_t Frequency, uint32_t Fr UI_PrintStringSmall(String, 70, 127, 3, 7, false); - uint8_t diff = max - min; - uint8_t tmp; - uint8_t line = max_index / 8; - uint8_t bit = max_index % 8; + line = max_index / 8; + bit = max_index % 8; for (uint8_t j = 54; j < 60; ++j) { gFrameBuffer[line][j] |= (1 << bit); } - for (uint8_t i = 0; i < 56; ++i) { - line = i / 8; - bit = i % 8; - tmp = max - rssi_val[i]; - tmp = (50 * tmp) / diff; - for (uint8_t j = 0; j < tmp; ++j) { - gFrameBuffer[line][j] |= (1 << bit); - } - } - spectrum_drawUI(Frequency, FrequencyStep); } +void spectrum_drawMinMaxDB(uint8_t* rssi_min, uint8_t* rssi_max) { + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); +} + #endif \ No newline at end of file diff --git a/ui/spectrum.h b/ui/spectrum.h index dba31cc2..31ea877e 100644 --- a/ui/spectrum.h +++ b/ui/spectrum.h @@ -17,7 +17,8 @@ #if defined(ENABLE_MINIMAL_SPECTRUM) void spectrum_drawUI(uint32_t Frequency, uint32_t FrequencyStep); -void spectrum_drawSpectrum(uint8_t rssi_val[56], uint32_t Frequency, uint32_t FrequencyStep); +void spectrum_drawSpectrum(uint8_t rssi_val[56], uint32_t Frequency, uint32_t FrequencyStep, uint8_t min, uint8_t max); +void spectrum_drawMinMaxDB(uint8_t* rssi_min, uint8_t* rssi_max); #endif #endif //FIRMWARE_UI_SPECTRUM_H diff --git a/ui/ui.c b/ui/ui.c index b8699610..f8910239 100644 --- a/ui/ui.c +++ b/ui/ui.c @@ -28,7 +28,7 @@ #include "ui/fmradio.h" #include "ui/inputbox.h" #include "ui/main.h" -#include "ui/menu.h" +#include "ui/menu_new.h" #include "ui/scanner.h" #include "ui/ui.h"