
#include "t1001.h"
#include "t1001_sleep.h"

// #define  XTAL            (48000000UL)     /* Oscillator frequency */
// #define  SYSTEM_CLOCK    (XTAL / 2U)
#define  EN_RTC()              (*(volatile uint32_t *)0x40080050 = 0x1)

typedef struct
{
    uint32_t const* src;
    uint32_t* dest;
    uint32_t  wlen;
} __copy_table_t;

typedef struct
{
    uint32_t* dest;
    uint32_t  wlen;
} __zero_table_t;

extern const __copy_table_t __copy_table_start__;
extern const __copy_table_t __copy_table_end__;
extern const __zero_table_t __zero_table_start__;
extern const __zero_table_t __zero_table_end__;

// extern uint32_t * __StackLimit;
// extern uint32_t * __StackTop;

// uint32_t SystemCoreClock = SYSTEM_CLOCK;  /* System Core Clock Frequency */

// void SystemCoreClockUpdate (void)
// {
//     SystemCoreClock = SYSTEM_CLOCK;
// }

void ram_init(void)
{
    for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable)
    {
        for(uint32_t i=0u; i<pTable->wlen; ++i)
        {
            pTable->dest[i] = pTable->src[i];
        }
    }

    for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable)
    {
        for(uint32_t i=0u; i<pTable->wlen; ++i)
        {
            pTable->dest[i] = 0u;
        }
    }

    #ifdef OMW_EN_OTA
    extern void omw_ota_reboot_chk();

    omw_ota_reboot_chk();
    #endif
    // for (uint32_t * ppp = __StackLimit; ppp < __StackTop; ppp++)
    // {
    //     ppp[0] = 0xF1E2D3C4;
    // }
}

// static void Cfg_clk()
// {
//    uint32_t  cpu_clk_src  = 1; //0:RC, 1:XTAL, 2: DPLL, 3: 32K
//    uint32_t  qspi_clk_src = 1;
//    // uint32_t  qspi_clk_frq = 3;

//    // *(volatile uint32_t *)0x42002000 = 2; //pll enable

//    //uart has been set to XTAL on bootloader

//    *(volatile uint32_t *)0x40000024 |= ((cpu_clk_src << 8) | (qspi_clk_src << 2));
// }

#ifndef OMW_ON_FPGA
//only call one time when power on
void PMU_OnChip_Init();

#ifdef OMW_EN_DEEP_SLEEP
void unused_gpio_mask_parse_and_set(unsigned int m);

#define UNUSED_GPIO_FUNC            0xA0        // 0xA0: high-impedance, 0x20: pull-up, 0x40: pull-down
// Description: parse GPIO mask, set gpio oe '0', set gpio function to UNUSED_GPIO_FUNC
__RAM_CODE_SECTION
void unused_gpio_mask_parse_and_set(unsigned int m){
    int i, j, t, fclr, fset;
    int *p;
    p = (int *)&(GPIO_ATF->GPIO_CFG_0);
    //---------------------------------------
    // GPIO OE
    //---------------------------------------
    t = GPIO_INOUT->GPIO_OE;
    t = t & (~m);
    GPIO_INOUT->GPIO_OE = t;
    //---------------------------------------
    // GPIO FUNC
    //---------------------------------------
    for(i=0; i<6; i++){
        // read
        t = *(p+i);
        fclr = 0xff;
        fset = UNUSED_GPIO_FUNC;
        // modify
        for(j=0; j<4; j++){
            if(m&1){
                t = t & (~fclr);
                t = t | ( fset);
            }
            m = m>>1;
            fclr = fclr<<8;
            fset = fset<<8;
        }
        // write
        *(p+i) = t;
    }
}

void force_sleep_wakeup_check();
#endif
#endif

void SystemInit (void)
{
    EN_RTC();

    REG_WRT(0x42000100, 0x1701);  //enable BB us tick

    #ifndef OMW_ON_FPGA
    #ifndef OMW_MCU_ONLY
    PMU_OnChip_Init();
    #endif
    #endif

	#ifdef OMW_EN_DEEP_SLEEP
    AON_CTRL->AON_CTRL0 = 0x7A;
    AON_CTRL->GOSLEEP   = 0;

    #ifdef OMW_EN_FORCE_SLEEP
    force_sleep_wakeup_check();
    #endif

    (void)omw_sleep_clr_wkup_rec();
	#endif

    *(volatile int *)(0x40000024) |= ((2 << 8) | (2 << 4));   //switch cpu clk to xtal@24M

    REG_WRT_BITS(0x40000024, 17, 16, 1);

    #ifndef OMW_EN_WDG
    SYS_CTRL->WDT_CFG = 0x00;
    #endif

    #ifdef OMW_EN_DEEP_SLEEP
    unused_gpio_mask_parse_and_set(OMW_UNUSED_GPIO_MASK);
    #endif
}

#ifdef OMW_BLE_V0
void rom_hook_register(int index, void* func)
{
    rom_hook_table[index] = func;
}
#endif

#if defined(OMW_BLE_V0) || defined(OMW_BLE_V0_2_0)
// ref: https://www.cnblogs.com/hancm/p/3638039.html
// ref: http://ftp.gnu.org/gnu/glibc/glibc-2.21.tar.gz
#undef RAND_MAX
#define RAND_MAX (32768)
static unsigned long int next = 1;

int xrand(void)
{
    next = next * 1103515245 + 12345;

    return (unsigned int)(next>>16) % (RAND_MAX);
}

void xsrand(unsigned int seed)
{
    next = seed;
}
#endif

#ifdef OMW_EN_DEEP_SLEEP
__RAM_CODE_SECTION
#endif
void delay_us(uint32_t us)
{
    volatile uint32_t cur_us = REG_RD(0x42000104);
    while(REG_RD(0x42000104) - cur_us < us);
}