/* UA1ZBE Custom Firmware for Quansheng UV-K5/K6 * Based on egzumer/uv-k5-firmware-custom * * Three modes: VFO, POCSAG decoder, Spectrum analyzer * Custom boot splash, RSSI indicator, direct frequency input * * Entry point: Main() */ #include #include #include #include "audio.h" #include "board.h" #include "misc.h" #include "radio.h" #include "settings.h" #include "app/app.h" #include "app/boot_splash.h" #include "app/mode.h" #include "app/dtmf.h" #include "bsp/dp32g030/gpio.h" #include "bsp/dp32g030/syscon.h" #include "driver/backlight.h" #include "driver/bk4819.h" #include "driver/gpio.h" #include "driver/system.h" #include "driver/systick.h" #include "driver/keyboard.h" #include "app/display_rssi.h" #include "helper/battery.h" #include "helper/boot.h" #include "ui/lock.h" #include "ui/welcome.h" #include "ui/menu.h" void _putchar(__attribute__((unused)) char c) { #ifdef ENABLE_UART extern void UART_Send(const uint8_t *p, uint16_t len); UART_Send((uint8_t *)&c, 1); #endif } void Main(void) { /* Enable clock gating of blocks we need */ SYSCON_DEV_CLK_GATE = 0 | SYSCON_DEV_CLK_GATE_GPIOA_BITS_ENABLE | SYSCON_DEV_CLK_GATE_GPIOB_BITS_ENABLE | SYSCON_DEV_CLK_GATE_GPIOC_BITS_ENABLE | SYSCON_DEV_CLK_GATE_UART1_BITS_ENABLE | SYSCON_DEV_CLK_GATE_SPI0_BITS_ENABLE | SYSCON_DEV_CLK_GATE_SARADC_BITS_ENABLE | SYSCON_DEV_CLK_GATE_CRC_BITS_ENABLE | SYSCON_DEV_CLK_GATE_AES_BITS_ENABLE | SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE; SYSTICK_Init(); BOARD_Init(); boot_counter_10ms = 250; /* Clear DTMF string */ memset(gDTMF_String, '-', sizeof(gDTMF_String)); gDTMF_String[sizeof(gDTMF_String) - 1] = 0; BK4819_Init(); BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent); SETTINGS_InitEEPROM(); SETTINGS_WriteBuildOptions(); SETTINGS_LoadCalibration(); RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD); RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD); RADIO_SelectVfos(); RADIO_SetupRegisters(true); for (unsigned int i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++) BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); BATTERY_GetReadings(false); /* Wait for user to release keys */ const BOOT_Mode_t BootMode = BOOT_GetMode(); if (BootMode == BOOT_MODE_F_LOCK) { extern bool gF_LOCK; gF_LOCK = true; } /* Count menu items */ gMenuListCount = 0; while (MenuList[gMenuListCount].name[0] != '\0') { if (!gF_LOCK && MenuList[gMenuListCount].menu_id == FIRST_HIDDEN_MENU_ITEM) break; gMenuListCount++; } if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) || KEYBOARD_Poll() != KEY_INVALID || BootMode != BOOT_MODE_NORMAL) { UI_DisplayReleaseKeys(); BACKLIGHT_TurnOn(); for (int i = 0; i < 50;) { i = (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && KEYBOARD_Poll() == KEY_INVALID) ? i + 1 : 0; SYSTEM_DelayMs(10); } gKeyReading0 = KEY_INVALID; gKeyReading1 = KEY_INVALID; gDebounceCounter = 0; } if (!gChargingWithTypeC && gBatteryDisplayLevel == 0) { FUNCTION_Select(FUNCTION_POWER_SAVE); if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) BACKLIGHT_TurnOff(); else BACKLIGHT_TurnOn(); gReducedService = true; } else { /* === CUSTOM BOOT SPLASH (2 seconds) === */ BACKLIGHT_TurnOn(); BOOT_SplashShow(); /* Initialize RSSI display */ RSSI_Init(); /* Initialize mode dispatcher — start in VFO mode */ MODE_Init(); gUpdateStatus = true; } /* === MAIN LOOP === */ while (true) { APP_Update(); if (gNextTimeslice) { /* Update RSSI periodically */ RSSI_Update(); /* Dispatch to current mode */ MODE_TimeSlice10ms(); if (gNextTimeslice_500ms) { MODE_TimeSlice500ms(); } } } }