/* 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 <stdint.h>
#include <string.h>
#include <stdio.h>

#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();
            }
        }
    }
}
