
#include "t1001.h"
#include "t1001_sleep.h"
#include "omw_gpio.h"
#include "t1002_otp_cfg.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__;

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

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

#if defined(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

void SystemInit (void)
{
    EN_RTC();

    REG_WRT(0x42000100, ((XTAL_FREQ - 1) << 8) + 1);  //enable BB us tick

    omw_otp_load_cfg();
    omw_otp_apply_cfg();

    #ifndef OMW_MCU_ONLY
    PMU_OnChip_Init();
    #endif

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

    #ifdef OMW_EN_DEEP_SLEEP
    unused_gpio_mask_parse_and_set(OMW_UNUSED_GPIO_MASK);
    #endif

    #ifdef OMW_EN_FORCE_SLEEP
    force_sleep_wakeup_check(OMW_GPIO_WAKEUP_MASK, OMW_GPIO_nWAKEUP_MASK, OMW_WHEN_SLEEP_GPIO_MASK);
    #endif

    (void)omw_sleep_clr_wkup_rec();
	#endif

    REG_WRT_MSK(0x40000024, (3 << 16 | 3 << 10), (1 << 16 | 1 << 10));
    // // UART CLK, default xtal 24m
    // REG_WRT_BITS(0x40000024, 11, 10, 1);
    // // OTP CLK
    // REG_WRT_BITS(0x40000024, 17, 16, 1);
    if((REG_RD_BYTE(0x40010212)) == 0) REG_WRT_BYTE(0x40010212, 0x20);


    #ifndef OMW_EN_WDG
    // wdt_en=0
    SYS_CTRL->WDT_CFG = 0x00;
    #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 + GET_CUR_TICK_US();

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

void delay_ms(uint32_t ms)
{
    delay_us(ms * 1000);
}
