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

#define XTAL (48000000UL) /* Oscillator frequency */
#define  SYSTEM_CLOCK    (XTAL / 2U)
//#define SYSTEM_CLOCK (XTAL)
#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

//    AON_CTRL->AON_CTRL0 = 0x7A;

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

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