#include "include.h"

/*
If the system clock is 24M, 24000000 can be written as sys_clk_geehy[SYS_24M]
If the system clock is 12M, 12000000 can be written as sys_clk_geehy[SYS_12M]
and so on...
*/
const u32 sys_clk_geehy[8]={2, 24, 48, 60, 80, 120, 147, 160};  //System clock selection

void adpll_init(u8 out_spr);

xcfg_cb_t xcfg_cb;
sys_cb_t sys_cb AT(.buf.bsp.sys_cb);
volatile u32 ticks_50ms;


#if FUNC_USBDEV_EN
#include "func_usbdev.h"
AT(.com_text.const)
const char usb_detect_str[] = "USB STA:%d\r\n";
AT(.com_text.detstr)
char pc_insert_str[] = "pc insert\n";
AT(.com_text.detstr)
char pc_remove_str[] = "pc remove\n";

extern volatile u16 msg;

AT(.com_text.detect)
void usb_detect(void)
{
    u8 usb_sta = usbchk_connect(USBCHK_ONLY_DEVICE);

    if (usb_sta == USB_PC_CONNECTED) {
        if (dev_online_filter(DEV_USBPC)) {
            msg = EVT_PC_INSERT;//msg_enqueue(EVT_PC_INSERT);
            printf(pc_insert_str);
        }
    } else {
        if (dev_offline_filter(DEV_USBPC)) {
            msg = EVT_PC_REMOVE;//msg_enqueue(EVT_PC_REMOVE);
            pc_remove();
            printf(pc_remove_str);
        }
    }
}
#endif // FUNC_USBDEV_EN

//timer tick interrupt(1ms)
AT(.com_text.timer)
void usr_tmr1ms_isr(void)
{
}

//timer tick interrupt(5ms)
AT(.com_text.timer)
void usr_tmr5ms_thread(void)
{
    tmr5ms_cnt++;

    //5ms timer process
//    bsp_key_scan();

#if DAC_EN
    dac_fade_process();
#endif

#if FUNC_USBDEV_EN
    usb_detect();
#endif // FUNC_USBDEV_EN

    //20ms timer process
    if ((tmr5ms_cnt % 4) == 0) {
    }

    //50ms timer process
    if ((tmr5ms_cnt % 10) == 0) {
        ticks_50ms++;
    }

    //100ms timer process
    if ((tmr5ms_cnt % 20) == 0)
    {
        if(sys_cb.sleep_delay != -1L && sys_cb.sleep_delay > 0)
            sys_cb.sleep_delay--;
        if(sys_cb.pwroff_delay != -1L && sys_cb.pwroff_delay > 0)
            sys_cb.pwroff_delay--;
    #ifdef FUNC_USBDEV_EN
        ude_tmr_isr();
    #endif // FUNC_USBDEV_EN
    }

    //500ms timer process
    if ((tmr5ms_cnt % 100) == 0) {
        sys_cb.cm_times++;
    }
}

AT(.com_text.timer)
void timer1_isr(void)
{
    if (TMR1CON & BIT(9)) {
        TMR1CPND = BIT(9);              //Clear Pending
        TMR1CON = 0;
    }
}

uint bsp_get_bat_level(void)
{
#if VBAT_DETECT_EN
    //Calculation method: level=(measured voltage - shutdown voltage)/(full voltage - shutdown voltage)/100)
    u16 bat_off = LPWR_OFF_VBAT * 100 + 2700;
    if (bat_off > sys_cb.vbat) {
        return 0;
    }
    uint bat_level = (sys_cb.vbat - bat_off) / ((4200 - bat_off) / 100);
//    printf("bat level: %d %d\n", sys_cb.vbat, bat_level);
    return bat_level;
#else
    return 100;
#endif
}

AT(.text.bsp.sys.init)
static void rtc_32k_configure(void)
{
    u32 temp = RTCCON0;
    temp &= ~BIT(6);                                //use RTC internal 32K osc
    temp |= BIT(2);                                 //CLK2M divide to RTC 32K clock source enable
    temp |= BIT(8);                                 //CLK2M in RTC power domain source select XOSC26M divide 8(3.25M)
    RTCCON0 = temp;
}

AT(.text.bsp.sys.init)
bool rtc_init(void)
{
    u32 temp;
    rtc_32k_configure();
    sys_cb.rtc_first_pwron = 0;
    temp = RTCCON0;
    if (temp & BIT(7)) {
        temp &= ~BIT(7);                            //clear first poweron flag
        RTCCON0 = temp;
        sys_cb.rtc_first_pwron = 1;
        printf("rtc 1st pwrup\n");
        return false;
    }

    return true;
}

//UART0 print information output GPIO selection, UART0 default G1 (PA7)
void uart0_mapping_sel(void)
{
    //Wait for uart0 to send
    if(UART0CON & BIT(0)) {
        while (!(UART0CON & BIT(8)));
    }

    GPIOADE  &= ~BIT(7);
    GPIOAFEN &= ~BIT(7);
    GPIOAPU  &= ~BIT(7);
    GPIOBFEN &= ~(BIT(2) | BIT(3));
    GPIOBPU  &= ~(BIT(2) | BIT(3));
    FUNCMCON0 = (0xf << 12) | (0xf << 8);           //clear uart0 mapping

#if (UART0_PRINTF_SEL == PRINTF_PA7)
    GPIOADE  |= BIT(7);
    GPIOAPU  |= BIT(7);
    GPIOADIR |= BIT(7);
    GPIOAFEN |= BIT(7);
    GPIOADRV |= BIT(7);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PA7;           //RX0 Map To TX0, TX0 Map to G1
#elif (UART0_PRINTF_SEL == PRINTF_PB2)
    GPIOBDE  |= BIT(2);
    GPIOBPU  |= BIT(2);
    GPIOBDIR |= BIT(2);
    GPIOBFEN |= BIT(2);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PB2;           //RX0 Map To TX0, TX0 Map to G2
#elif (UART0_PRINTF_SEL == PRINTF_PB3)
    GPIOBDE  |= BIT(3);
    GPIOBPU  |= BIT(3);
    GPIOBDIR |= BIT(3);
    GPIOBFEN |= BIT(3);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PB3;           //RX0 Map To TX0, TX0 Map to G3
#elif (UART0_PRINTF_SEL == PRINTF_PE7)
    GPIOEDE  |= BIT(7);
    GPIOEPU  |= BIT(7);
    GPIOEDIR |= BIT(7);
    GPIOEFEN |= BIT(7);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PE7;           //RX0 Map To TX0, TX0 Map to G4
#elif (UART0_PRINTF_SEL == PRINTF_PA1)
    GPIOADE  |= BIT(1);
    GPIOAPU  |= BIT(1);
    GPIOADIR |= BIT(1);
    GPIOAFEN |= BIT(1);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PA1;           //RX0 Map To TX0, TX0 Map to G5
#elif (UART0_PRINTF_SEL == PRINTF_PE0)
    GPIOEDE  |= BIT(0);
    GPIOEPU  |= BIT(0);
    GPIOEDIR |= BIT(0);
    GPIOEFEN |= BIT(0);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PE0;           //RX0 Map To TX0, TX0 Map to G6
#elif (UART0_PRINTF_SEL == PRINTF_PF2)
    GPIOFDE  |= BIT(0);
    GPIOFPU  |= BIT(0);
    GPIOFDIR |= BIT(0);
    GPIOFFEN |= BIT(0);
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_PF2;           //RX0 Map To TX0, TX0 Map to G7
#elif (UART0_PRINTF_SEL == PRINTF_VUSB)
    FUNCMCON0 = URX0MAP_TX | UTX0MAP_VUSB;          //RX0 Map To TX0, TX0 Map to G8
#endif
}

//Contents initialized before opening user timer
AT(.text.bsp.sys.init)
static void bsp_var_init(void)
{
    memset(&sys_cb, 0, sizeof(sys_cb));

    sys_cb.sleep_time = -1L;
    sys_cb.pwroff_time = -1L;
    if (xcfg_cb.sys_sleep_time != 0) {
        sys_cb.sleep_time = (u32)xcfg_cb.sys_sleep_time * 10;   //100ms
    }
    if (xcfg_cb.sys_off_time != 0) {
        sys_cb.pwroff_time = (u32)xcfg_cb.sys_off_time * 10;    //100ms
    }

    sys_cb.sleep_delay = -1L;
    sys_cb.pwroff_delay = -1L;
    sys_cb.sleep_en = 0;

#if USER_PWRKEY
    if (xcfg_cb.user_pwrkey_en || PWRKEY_2_HW_PWRON) {
        sys_cb.wko_pin_en = 1;
    }
#endif // USER_PWRKEY

#if USER_IOKEY
    if (xcfg_cb.user_iokey_en) {
        //If PB5 pin is selected for IO KEY
        if ((xcfg_cb.iokey_io0 == 28) || (xcfg_cb.iokey_io1 == 28) || (xcfg_cb.iokey_io2 == 28)) {
            sys_cb.wko_pin_en = 1;
        }
    }
#endif // USER_IOKEY

    //The PWRKEY analog hard switch needs to turn off the functions such as pressing and holding for 10s to reset, power-on for the first time, and pressing and holding for 5 seconds to pair.
    if (PWRKEY_2_HW_PWRON) {
        xcfg_cb.powkey_10s_reset = 0;
        xcfg_cb.bt_pwrkey_nsec_discover = 0;
    }

    dev_init(FUNC_USBDEV_EN*0x10);
    #if DAC_EN
    dac_cb_init((DAC_CH_SEL & 0x0f) | ((u8)DAC_LDOH_SEL << 4) | (0x200 * DAC_FAST_SETUP_EN) | (0x400 * DAC_VCM_CAPLESS_EN) | (0x800 * DACVDD_BYPASS_EN) | (0x1000 * 0));
    #endif
}

AT(.text.bsp.sys.init)
static void bsp_io_init(void)
{
    GPIOADE = BIT(7); //UART
    GPIOBDE = 0;
    GPIOEDE = 0;
    GPIOFDE = 0;
    GPIOGDE = 0x3F; //MCP FLASH

//    tkey_sw_reset();

    uart0_mapping_sel();       //Debug UART IO selection or shutdown
    #if DAC_EN
    loudspeaker_mute_init();
    #endif
}

void bsp_get_xosc_xcfg(u8 *osci_cap, u8 *osco_cap, u8 *both_cap)
{
    *osci_cap = xcfg_cb.osci_cap;
    *osco_cap = xcfg_cb.osco_cap;
    *both_cap = xcfg_cb.osc_both_cap;
}

AT(.text.bsp.sys.init)
void bsp_update_init(void)
{
    /// config
    if (!xcfg_init(&xcfg_cb, sizeof(xcfg_cb))) {           //Get configuration parameters
        printf("xcfg init error\n");
    }

    // io init
    bsp_io_init();

    // var init
    bsp_var_init();

    // peripheral init
    rtc_init();
    param_init(sys_cb.rtc_first_pwron);

    //Crystal oscillator configuration
    xosc_init();

    sys_set_tmr_enable(1, 1);

    adpll_init(0);
}

AT(.com_text.sys)
bool spiflash_speed_up_en(void)   //SPI FLASH speed up. Some FLASH does not support speed increase
{
#if SPIFLASH_SPEED_UP_EN
    return true;
#else
    return false;
#endif
}


AT(.text.bsp.sys.init)
void bsp_sys_init(void)
{
    /*Power-on transmission test serial port*/
    u32 lvdcon = LVDCON;
    printf("Hello GW3323: %x\n", lvdcon);
    if(lvdcon & BIT(18))        printf("WKO reset\n");
    else if(lvdcon & BIT(17))   printf("VUSB reset\n");
    else if(lvdcon & BIT(16))   printf("WDT reset\n");
    else if(lvdcon & 0xf00)     printf("SW reset\n");

    /// config
    if (!xcfg_init(&xcfg_cb, sizeof(xcfg_cb))) {           //Get configuration parameters
        printf("xcfg init error\n");
    }
    else
        printf("xcfg init ok\n");

    // io init
    bsp_io_init();

    // var init
    bsp_var_init();

    // power init
    pmu_init((BUCK_CURR_LIMIT_DIS << 7) | BUCK_MODE_EN);
    adpll_init(0);
    // clock init
    set_sys_clk(SYS_CLK_SEL);

    // peripheral init
    rtc_init();
    param_init(sys_cb.rtc_first_pwron);

    //Crystal oscillator configuration
    xosc_init();

#if USB_SUPPORT_EN
    CLKGAT0 = BIT(28)|BIT(26)|BIT(25)|BIT(24)|BIT(23)|BIT(22)|BIT(20)|BIT(19)|BIT(18)|BIT(17)|BIT(16)|BIT(13)|BIT(12)|BIT(10)|BIT(8)|BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2)|BIT(1)|BIT(0);
    CLKGAT1 = BIT(27)|BIT(25)|BIT(24)|BIT(23)|BIT(16)|BIT(15)|BIT(12)|BIT(5);
//    CLKGAT2 = 0;

    CLKCON0 |= BIT(17)|BIT(18);     //HUART
    CLKCON1 |= BIT(10);             //USB
    CLKGAT0 |= BIT(27);             //RECSRC_CLK, SRC1

    ///usb clock
    CLKGAT0 |= BIT(14);
#endif
//    CLKGAT0 |= BIT(9);             //SDCLK
    if (POWKEY_10S_RESET) {
        RTCCON10 |= BIT(10);        //clear 10s pending
        RTCCON12 = 0;               //10S Reset Enable
        RTCCON0 |= BIT(8);
    } else {
        RTCCON12 = 0x0a;            //10S Reset Disable
    }

    /// enable user timer for display & dac
    sys_set_tmr_enable(1, 1);

    WDT_DIS();           /*Turn off the watchdog*/
}

