#include "include.h"
#include "driver_lowpwr.h"
#include "bsp_saradc_key.h"
#include "usb_com.h"
#include "usb_hid.h"
#include "usb_audio.h"
#include "usb_vendor.h"

xcfg_cb_t xcfg_cb;
sys_cb_t sys_cb AT(.buf.bsp.sys_cb);
u16 tmr5ms_cnt;

#if WIRELESS_TRANSMIT_EN
bool bTransmitEn = true;
#else
bool bTransmitEn = false;
#endif // WIRELESS_TRANSMIT_EN

AT(.text.bsp.sys.dbg)
void sys_flash_guid_dump(void)
{
    flash_id_t flash_id;

    os_spiflash_id_get(flash_id);

    printf("Flash GUID: ");
    print_r(flash_id, sizeof(flash_id_t));
}

void sys_ram_info_dump(void)
{
    extern u32 __comm_size;
    extern u32 __bss_size;
    extern u32 __bram_size;
    extern u32 __heap_size;

    extern u32 __bram_vma;
    extern u32 __bram_ram_size;
    extern u32 __data_vma;
    extern u32 __data_ram_size;
    extern u32 __comm_vma;
    extern u32 __comm_ram_size;

#if COMM_EX_SIZE
    extern u32 __commEx_size;
    extern u32 __commEx_vma;
    extern u32 __commEx_ram_size;
    #define commEx_free     ((u32)&__commEx_ram_size - (u32)&__commEx_size)
    #define __show(...)     printf(__VA_ARGS__)
#else
    #define commEx_free     0
    #define __show(...)
#endif

    u32 comm_free  = (u32)&__comm_ram_size - (u32)&__comm_size;
    u32 bss_free = (u32)&__data_ram_size - (u32)&__bss_size - (u32)&__heap_size;
    u32 bram_free = (u32)&__bram_ram_size - (u32)&__bram_size;
    u32 ram_total = comm_free + commEx_free + bss_free + bram_free;

    printf("Ram_info:\n");
    printf("bss:    remain:%6d(Byte), total:%6d(Byte), range:[0x%x - 0x%x]\n", bss_free,  (u32)&__data_ram_size,  (u32)&__data_vma, (u32)&__data_vma + (u32)&__data_ram_size);
    printf("comm:   remain:%6d(Byte), total:%6d(Byte), range:[0x%x - 0x%x]\n", comm_free, (u32)&__comm_ram_size, (u32)&__comm_vma, (u32)&__comm_vma + (u32)&__comm_ram_size);
    __show("commEx: remain:%6d(Byte), total:%6d(Byte), range:[0x%x - 0x%x]\n", commEx_free, (u32)&__commEx_ram_size, (u32)&__commEx_vma, (u32)&__commEx_vma + (u32)&__commEx_ram_size);
    printf("bram:   remain:%6d(Byte), total:%6d(Byte), range:[0x%x - 0x%x]\n", bram_free, (u32)&__bram_ram_size, (u32)&__bram_vma, (u32)&__bram_vma + (u32)&__bram_ram_size);
    printf("remain_total: %dK\n",ram_total / 1024);
}

#if USB_EN
AT(.com_text.dev.detect)
void usb_detect(void)
{
    int evt = usb_bus_event_check();

    switch (evt) {
        case USB_BUS_EVENT_DISCONNECT:
            msg_enqueue(MSG_SYS_PC_REMOVE);
            break;

        case USB_BUS_EVENT_CONNECT:
            msg_enqueue(MSG_SYS_PC_INSERT);
            break;

        default:
            break;
    }
}
#endif

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

#if BSP_KEY_EN
    bsp_key_scan(0);
    bsp_key_status_check();
#endif

#if USB_EN
    usb_detect();
#endif

    //100ms timer process
    if ((tmr5ms_cnt % 20) == 0) {
        lowpwr_tout_ticks();
    }

    //500ms timer process
    if ((tmr5ms_cnt % 100) == 0) {
        msg_enqueue(MSG_SYS_500MS);
    }

    //1s timer process
    if ((tmr5ms_cnt % 200) == 0) {
        msg_enqueue(MSG_SYS_1S);
    }
}

AT(.text.bsp.sys.init)
static void bsp_var_init(void)
{
#if SYS_SLEEP_LEVEL
    sys_cb.sleep_time = -1L;
    sys_cb.sleep_delay = -1L;

    if (SYS_SLEEP_TIME != 0) {
        sys_cb.sleep_time = (u32)SYS_SLEEP_TIME * 10;   //100ms为单位
        sys_cb.sleep_delay = sys_cb.sleep_time;
    }
#endif

#if SYS_OFF_TIME
    sys_cb.pwroff_time = -1L;
    sys_cb.pwroff_delay = -1L;

    if (SYS_OFF_TIME != 0) {
        sys_cb.pwroff_time = (u32)SYS_OFF_TIME * 10;    //100ms为单位
        sys_cb.pwroff_delay = sys_cb.pwroff_time;
    }
#endif


    if(!xcfg_cb.ft_osc_cap_en || (xcfg_cb.osci_cap == 0 && xcfg_cb.osco_cap == 0)) {        //没有过产测时，使用自定义OSC电容
        xcfg_cb.osci_cap = xcfg_cb.uosci_cap;
        xcfg_cb.osco_cap = xcfg_cb.uosco_cap;
        xcfg_cb.osc_both_cap = xcfg_cb.uosc_both_cap;
    }

    msg_queue_init();
}

void power_on_check(void)
{
    u32 power_on_check_time = SYS_PWRUP_TIME;

    if (sys_cb.wakeup_reason != WK_LP_WK0 || power_on_check_time == 0) {
        return;
    }

#if BSP_KEY_EN

    u32 tick = tick_get();
    u16 key;
    u16 cnt_up = 0;

    while (1) {
        WDT_CLR();
        delay_5ms(1);

        key = bsp_key_scan(1);

        if (!tick_check_expire(tick, power_on_check_time)) {
            if (key != KEY_ID_PP) {
                cnt_up++;
                if(cnt_up > 5){
                    func_pwroff();
                }
            }else{
                cnt_up = 0;
            }
        } else {
            bsp_key_set_power_on_flag(true);
            return;
        }
    }
#endif
}

AT(.text.bsp.sys.init)
void bsp_sys_init(void)
{
    uint8_t pmu_cfg = BUCK_MODE_EN * PMU_CFG_BUCK_EN;

#if !BSP_CHARGE_EN
    pmu_cfg |= PMU_CFG_CHARGE_DIS;
#endif

#if VUSB_2_VDDIO_EN
    pmu_cfg |= PMU_CFG_VUSB_TO_VDDIO;
#endif

    if (!xcfg_init(&xcfg_cb, sizeof(xcfg_cb))) {           //获取配置参数
        printf("xcfg init error\n");
    }

    bsp_var_init();

#if BSP_SARADC_EN
    bsp_saradc_init();
#endif

#if BSP_KEY_EN
    bsp_key_init();
#endif

    power_on_check();

    // power init
    pmu_init(pmu_cfg);

    // clock init
    sys_clk_set(SYS_CLK_SEL);

    bsp_param_init();

    xosc_init();

    // enable user timer
    sys_set_tmr_enable(1, 1);

#if BSP_CHARGE_EN
    bsp_charge_init();
#endif

#if BSP_VBAT_DETECT_EN
    bsp_vbat_detect_init();
#endif // BSP_VBAT_DETECT_EN

#if BSP_SDADC_EN
    pmu_set_vddio(PMU_VDDIO_LEVEL);
    bsp_sdadc_init();
#if AUDIO_OUT_LOCAL_DEBUG
    bsp_sddac_init();
#endif // AUDIO_OUT_LOCAL_DEBUG
#endif // BSP_SDADC_EN

#if BSP_MOUSE_SENSEN_EN
    bsp_mouse_sense_init();
#endif // BSP_MOUSE_SENSEN_EN

#if USB_EN
    usb_device_init();
#endif // USB_EN

    touch_init();

    func_cb.sta = FUNC_WIRELESS;

    printf("%s, %d\n",__func__, func_cb.sta);

    WDT_EN();
}

void bsp_periph_init(void)
{
#if BSP_UART_DEBUG_EN
    bsp_uart_debug_init();
#endif

#if BSP_SARADC_EN
    bsp_saradc_init();
#endif

#if BSP_ADKEY_EN
    bsp_adkey_init();
#endif

#if BSP_VBAT_DETECT_EN
    bsp_vbat_detect_init();
#endif

#if BSP_SDADC_EN
    bsp_sdadc_init();
#if AUDIO_OUT_LOCAL_DEBUG
    bsp_sddac_init();
#endif // AUDIO_OUT_LOCAL_DEBUG
#endif // BSP_SDADC_EN

#if BSP_MOUSE_SENSEN_EN
    bsp_mouse_sense_init();
#endif // BSP_MOUSE_SENSEN_EN

#if USB_EN
    usb_init();
#endif
}
