#include "omw_config.h"
#include "omw_spim.h"
#include "omw_spis.h"
#include "omw_uart.h"
#include "omw_flash.h"
#include "omw_cmd.h"
#include "omw_timer.h"
#include "omw_iic.h"
#include "omw_sdma.h"
#include "omw_gpadc.h"
#include "omw_sys.h"
#include "omw_wdt.h"
#include "omw_clkcal.h"
#include "omw_sys.h"


#ifdef OMW_HAS_LOG_UART
#include "omw_dbg.h"
#endif

#ifdef OMW_TIMER
#define PWM_HIGH_LEVE_CYCLES        100
#define PWM_LOW_LEVE_CYCLES         500
#endif

#ifdef OMW_WDT
#define WDT_FEED_THRESHOLD_VALUE    500       // ms
#define WDT_FEED_TIME               30000     // ms
#endif

#ifdef OMW_IIC
#define IIC_DEVICE_ADDR             0x50      
#endif

#ifdef OMW_INTR
#define NVIC_EnableIRQ(IRQn) csi_vic_enable_irq(IRQn)
#define NVIC_SetPriority(IRQn, priority) csi_vic_set_prio(IRQn, priority)
#endif

VTIMER_HandleType  app_timer;
int app_counts;

void app_timeout_cb(void* param)
{
    printf("print in timer out callback: %d\n", app_counts);

    VTIMER_StartTimerMs(&app_timer, 10*1000);
    app_counts++;
}

#ifdef OMW_CMD_CTRL
#define CMD_UART_FIFO_BUF_SIZE  128   //need power of 2
uint8_t  cmd_uart_buf[CMD_UART_FIFO_BUF_SIZE];
void app_cmd_uart_rx_init(uint8_t *data, uint16_t size)
{
    //when enable with IT MODE, need to config a FIFO BUF to uart,
    //and call omw_cmd_uart_it_rx to rcv data.
    //otherwise, not need to config a FIFO BUF to uart, and call omw_cmd_uart_rx to rcv data
    omw_cmd_uart_set_rx_fifo(data, size);
    omw_cmd_uart_enable(1); //IT MODE
    NVIC_SetPriority(UART1_IRQn, IRQ_CRITICAL_PRIORITY);
    NVIC_EnableIRQ(UART1_IRQn);
}
#endif

int main(void)
{
    #ifdef OMW_HAS_LOG_UART
    omw_dbg_init();
    #endif
    printf("Enter main!\n");

    VTIMER_Init();
    app_timer.callback = app_timeout_cb;
	
    omw_set_irq_prio(RTC_IRQn, IRQ_HIGH_PRIORITY);
    omw_enable_irq(RTC_IRQn);
	
    VTIMER_StartTimerMs(&app_timer, 10*1000); //start a Timer, 10 seconds
    // VTIMER_startTimerUs(&app_timer, 10*1000*1000); //when call us API, the precision < 32us
	
//	while(1);


    #ifdef OMW_CMD_CTRL
    app_cmd_uart_rx_init(cmd_uart_buf, CMD_UART_FIFO_BUF_SIZE);
    uint8_t rx_buf[8];
	while(1) {
		uint16_t rl = omw_cmd_uart_it_rx(rx_buf, 4);
		if (rl == 4)
		{//rx ok
			//do something
			omw_cmd_uart_send(rx_buf, 4);
		}
	}
    #endif


    #ifdef OMW_SPIS
    omw_spis_init(OMW_SPIS0_BASE, OMW_SPIS_3LINES);
    uint8_t spis_rcv_buf[8];
    uint8_t spis_rl = 0;
    do
    {
        uint8_t cur_rl_spis = omw_spis_rcv(OMW_SPIS0_BASE, spis_rcv_buf + spis_rl, 8 - spis_rl);
        spis_rl += cur_rl_spis;
    } while (spis_rl < 8);

    omw_spis_send(OMW_SPIS0_BASE, spis_rcv_buf, 8);
    #endif


    #ifdef OMW_SPIM0//OR OMW_SPIM1
    omw_spim_init(OMW_SPIM0_BASE,OMW_SPIM_4LINES,4);
    uint8_t spim_send_buf[8];
    uint8_t spim_rl = 0;
    
    omw_spim_send(OMW_SPIM0_BASE,spim_send_buf,8);
    
    do
    {
        uint8_t cur_rl_spim = omw_spim_rcv(OMW_SPIM0_BASE, spim_send_buf + spim_rl, 8 - spim_rl);
        spim_rl += cur_rl_spim;
    } while (spim_rl < 8);
    #endif


    #ifdef OMW_IIC
    int eeprom_addr = 0x50, eeprom_page_addr = 0x70, eeprom_data = 0x40,read_val;

    //与eeprom交互例程
	iic_initypedef iic_initstruct;
	iic_initstruct.iic_mode = OMW_IIC_MODE_MASTER;                      
	iic_initstruct.iic_speed_mode = OMW_IIC_SPEED_MODE_FS;              //速度模式配置
	iic_initstruct.iic_target_addr_mode = OMW_IIC_TARGET_ADDR_MODE_7BIT;//主机寻址模式配置，用作slave时不需要配置
	iic_initstruct.iic_target_addr = eeprom_addr ;                             //主机地址配置，用作slave时不需要配置 iic使能位置位时不可修改
	iic_initstruct.iic_slave_addr_mode = OMW_IIC_SLAVE_ADDR_MODE_7BIT;  //从机寻址模式配置，用作master时不需要配置
	iic_initstruct.iic_slave_addr = 0;                                  //从机自身地址配置，用作master时不需要配置
	iic_initstruct.iic_clk_frequency = OMW_IIC_CLK_FREQUENCY_400K;      //时钟速率配置
	iic_initstruct.iic_rx_threshold = 0x07;                             //RX_FIFO水线配置
	iic_initstruct.iic_tx_threshold = 0x07;                             //TX_FIFo水线配置
	
	
	iic_cmd(DISABLE);
	iic_intr_cmd(OMW_IIC_INTR_ALL,DISABLE);
	iic_init(&iic_initstruct);
	iic_cmd(ENABLE);
	iic_send_byte(eeprom_page_addr);
	iic_send_byte(eeprom_data);
    omw_rtc_delay_ms(10);
	iic_send_byte(eeprom_page_addr);
	read_val = iic_receive_byte();
	if(read_val == eeprom_data)
	    printf("read value correct");
    else 
		printf("read value error");
    #endif


	#ifdef OMW_GPIO
	//GPIO INPUT
		omw_gpio_init(OMW_GPIO_PIN4,OMW_GPIO_MODE_IN_FLOATING,OMW_GPIO_DRIVE_STRENTH0);             //GPIO4 INPUT
		int value = omw_gpio_read_input_data(OMW_GPIO_PIN4);       //READ GPIO4 INPUT DATA
		printf("GPIO4 INPUT VALUE: %d", value);
	//GPIO OUTPUT
		omw_gpio_set_output_en(OMW_GPIO_PIN5,ENABLE); //GPIO OUTPUT ENABLE
		omw_gpio_set_output(OMW_GPIO_PIN5,HIGH);       //GPIO OUTPUT HIGH
	    omw_gpio_set_output(OMW_GPIO_PIN5,LOW);        //GPIO OUTPUT LOW
	//GPIO4 INTR
	    NVIC_SetPriority(GPIO_IRQn, IRQ_CRITICAL_PRIORITY);
        NVIC_EnableIRQ(GPIO_IRQn);
	    omw_gpio_set_it_en(OMW_GPIO_PIN4,ENABLE);
		omw_gpio_set_it(OMW_GPIO_PIN4,OMW_GPIO_IT_RISING,ENABLE);

	#endif

    #ifdef OMW_TIMER
	    //timer4 计时1ms示例
//	    NVIC_SetPriority(TIMER4_IRQn, IRQ_CRITICAL_PRIORITY);
//        NVIC_EnableIRQ(TIMER4_IRQn);
//
//        TIMER_InitTypeDef timer_struct_4;
//        omw_timer_struct_init(&timer_struct_4);
//         timer_struct_4.timer_mode = OMW_TIMER_MODE_USER_DEFINED;  //用户自己自由定义count数值，free_mode模式下，计数器数值为最大值65535
//         timer_struct_4.timer_clk_divide = OMW_TIMER_CLK_DIVIDE_2; //时钟分频，默认为二分频
//         timer_struct_4.timer_clk = OMW_TIMER_CLK_SEL_XTAL24M;    //时钟选择
//         timer_struct_4.timer_loadcount = 12000;  //定义count数值,当前设定下以6M时钟计数器自减
//         timer_struct_4.timer_pwm_en = OMW_TIMER_PWM_DISABLE; //pwm使能位
//	     omw_timer_en(TIMER4,DISABLE);
//         omw_timer_init(TIMER4,&timer_struct_4);
//		 omw_timer_it_en(TIMER4,ENABLE);
//		 omw_timer_en(TIMER4,ENABLE);

	    //timer5计时1us示例
	    NVIC_SetPriority(TIMER5_IRQn, IRQ_CRITICAL_PRIORITY);
        NVIC_EnableIRQ(TIMER5_IRQn);

        TIMER_InitTypeDef timer_struct_5;
         omw_timer_struct_init(&timer_struct_5);
         timer_struct_5.timer_mode = OMW_TIMER_MODE_USER_DEFINED;  //用户自己自由定义count数值，free_mode模式下，计数器数值为最大值65535
         timer_struct_5.timer_clk_divide = OMW_TIMER_CLK_DIVIDE_2; //时钟分频，默认为二分频
         timer_struct_5.timer_clk = OMW_TIMER_CLK_SEL_PLL48M;    //时钟选择
         timer_struct_5.timer_loadcount = 12;  //定义count数值,当前设定下以6M时钟计数器自减
         timer_struct_5.timer_pwm_en = OMW_TIMER_PWM_DISABLE; //pwm使能位
	     omw_timer_en(TIMER5,DISABLE);
         omw_timer_init(TIMER5,&timer_struct_5);
		 omw_timer_it_en(TIMER5,ENABLE);
		 omw_timer_en(TIMER5,ENABLE);

		//timer6作pwm
//        TIMER_InitTypeDef timer_struct_6;
//        omw_timer_struct_init(&timer_struct_6);
//        timer_struct_6.timer_mode = OMW_TIMER_MODE_USER_DEFINED;
//        timer_struct_6.timer_clk_divide = OMW_TIMER_CLK_DIVIDE_2;
//        timer_struct_6.timer_clk = OMW_TIMER_CLK_SEL_XTAL24M;
//        timer_struct_6.timer_loadcount = 70;
//        timer_struct_6.timer_pwm_en = OMW_TIMER_PWM_ENABLE;
//        timer_struct_6.timer_loadcount2 = 30;
//        timer_struct_6.timer_pwm0n100_en = OMW_TIMER_PWM0N100_ENABLE;
//		omw_timer_gpio_init(OMW_TIMER6_GPIO6);
//        omw_timer_en(TIMER6,DISABLE);
//        omw_timer_init(TIMER6,&timer_struct_6);
//        omw_timer_it_en(TIMER6,DISABLE);
//        omw_timer_en(TIMER6,ENABLE);

	#endif

    #ifdef OMW_GPADC

    GPADC_InitTypeDef ADC_init;
	omw_gpadc_structinit(&ADC_init);
	
	ADC_init.gpadc_att_sel = OMW_GPADC_ATT_SEL_QUARTER;  //输入分压器控制
    ADC_init.gpadc_diff_en = DISABLE;            //差分输入使能
    ADC_init.gpadc_vin_sel= OMW_GPADC_VIN_SEL_INTERNAL_REFERENCE_VOLTAGE_0V9;  //差分输入vin
    ADC_init.gpadc_vip_sel = OMW_GPADC_VIP_SEL_GPIO6;                //差分输入vip

    ADC_init.gpadc_avg_win = 7;                  //GPADC计算平均窗口，2** GPADC平均窗口，最大256
    ADC_init.gpadc_timer_sel = 0;                //timer选择
    ADC_init.gpadc_timer_mode = 0;               //timer采样模式使能
    ADC_init.gpadc_cont_mode = OMW_GPADC_TRIG_ONE_SAMPLE;                //采样模式
    ADC_init.gpadc_samp_en = ENABLE;             //寄存器采样使能
    ADC_init.gpadc_dma_en = 0;                   //gpadc_dma模式使能

    ADC_init.gpadc_int_interval = 0;             //dma中断间隔，
    ADC_init.gpadc_bk_num = OMW_GPADC_BK_NUM_8KB;//RAM空间大小设置
    ADC_init.gpadc_start_bk = 0;                 //RAM起始块数选择
    ADC_init.gpadc_signext = OMW_GPADC_SIGNEXT_UNSIGNED;                  //RAM数据符号选择
    ADC_init.gpadc_format = OMW_GPADC_FORMAT_SIGNED_TWO_COMPLEMENT;       //数据格式选择
    ADC_init.gpadc_store_mode = OMW_GPADC_STORE_MODE_16BIT;               //数据长度设置

    ADC_init.gpadc_clk_pre = 0;    //adc采样预延时
    ADC_init.gpadc_clk_div = 3;    //adc时钟分频
    ADC_init.gpadc_clk_out_pol = OMW_GPADC_CLK_OUT_POL_HIGH;  //adc时钟初值设定
    ADC_init.gpadc_clk_out_inv = OMW_GPADC_CLK_OUT_INV_NORMAL;//adc时钟极性设置
    ADC_init.gpadc_clk_samp_inv = OMW_GPADC_CLK_SAMP_INV_RISE;//adc时钟采样边沿选择
    ADC_init.gpadc_clk_en = ENABLE;  //adc时钟使能
    ADC_init.gpadc_clk_autocg = ENABLE; //adc采样时钟自动门使能
    ADC_init.gpadc_clk_sel = OMW_GPADC_CLK_SEL_XTAL24M;  //adc采样时钟选择

//	omw_gpadc_itconfig(ENABLE,OMW_GPADC_BASE);
    omw_gpadc_init(&ADC_init,OMW_GPADC_BASE);
	omw_gpadc_cmd(ENABLE,OMW_GPADC_BASE);
	int adc_value = omw_gpadc_get_samp();
	printf("dst adc value: %d", adc_value);


	#endif

	#ifdef OMW_SDMA

	SDMA_TASK_InitTypeDef Normal_case;

	Normal_case.int_en = SDMA_TASK_INTR_DISABLE;             //dma_task中断使能
	Normal_case.dma_word_en = SDMA_TASK_TRANSACTION_BYTE;    //数据传输格式
	Normal_case.task_format = SDMA_TASK_MODE_NORMAL;         //数据传输模式
	Normal_case.cmd_war = SDMA_TASK_CMD_WAR_DISABLE;         //cmd传输模式下 使能该位会将cmd命令地址原先数据取出，并与写入值计算后填入命令地址
	Normal_case.cmd_pre_en = SDMA_TASK_CMD_PRE_DISABLE;      //cmd传输模式下 使能该位会在数据传输前进行cmd传输
	Normal_case.trigger_index = 31;                     //下一个task触发序号，31为默认不触发
	Normal_case.src_add_inc_en = SDMA_TASK_SRC_ADD_INCRE_ENABLE;  //源数据地址自增使能
	Normal_case.dst_add_inc_en = SDMA_TASK_DST_ADD_INCRE_ENABLE;  //目标数据地址自增使能
	Normal_case.src_begin_upd_en = SDMA_TASK_SRC_BEGIN_UDT_DISABLE;  //源数据地址更新使能
	Normal_case.dst_begin_upd_en = SDMA_TASK_DST_BEGIN_UDT_DISABLE;  //目标数据地址更新使能
    Normal_case.num_bytes = 1;                        //传输数据长度
	Normal_case.src_addr = 0x40010204;                  //源数据地址
	Normal_case.dst_addr = 0x40010205;                  //目标数据地址
	Normal_case.cmd_addr = 0;                           //cmd命令存入地址
	Normal_case.cmd_wdata = 0;                 //cmd命令存入数据
	Normal_case.cmd_mask = 0;                  //cmd命令存入
	Normal_case.fifo_size = 0;                          //fifo模式传输轮询长度
	Normal_case.fifo_mode_src = SDMA_TASK_FIFO_MODE_SRC_SPACE_DISABLE;                     //fifo模式源数据轮询使能
	Normal_case.fifo_mode_dst = SDMA_TASK_FIFO_MODE_DST_SPACE_DISABLE;                     //fifo模式目标数据轮询使能

    *(volatile uint8_t*)(0x40010204) = 0x18;   //源数据输入

    omw_sdma_init();
	omw_sdma_task_init(&Normal_case,(uint32_t*) SDMA_TaskTable[0]);

	omw_sdma_cmd(ENABLE);
	omw_sdma_value_set(SDMA_ALL,RESET);
	omw_sdma_value_set(SDMA0,SET);
	omw_sdma_action(SDMA_ACTION_ADD);
	while(omw_sdma_status_bit(SDMA0));
	omw_sdma_cmd(DISABLE);
	int dst_data =  *(volatile uint8_t*)(0x40010205);
	printf("dst data value: %d", dst_data);

	#endif

    #ifdef OMW_WDT
	    omw_wdt_en(ENABLE);
		do
		{
		 omw_wdt_feed(WDT_FEED_TIME);
		}while(omw_wdt_time_value() < WDT_FEED_THRESHOLD_VALUE);
	#endif

    #ifdef OMW_SYS
        int sys_i, sys_t0, sys_t1, sys_dly;
        // reset flag
        sys_t0 = omw_get_reset_flag();
        printf("Reset flag first get: 0x%03x\n", sys_t0);
        omw_clear_reset_flag(sys_t0);
        omw_rtc_delay_ms(1); // delay at least 100us
        sys_t0 = omw_get_reset_flag();
        printf("Reset flag after clear: 0x%03x\n", sys_t0);
        // clk switch test
        sys_dly = 200;
        for(sys_i=0; sys_i<1000; sys_i++){
            // RC24M
            omw_set_sys_clk(SYS_CLK_RC24M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
            // XTAL24M
            omw_set_sys_clk(SYS_CLK_XTAL24M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
            // PLL48M
            omw_set_sys_clk(SYS_CLK_PLL48M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
            // PLL24M
            omw_set_sys_clk(SYS_CLK_PLL24M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
            // PLL12M
            omw_set_sys_clk(SYS_CLK_PLL12M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
            // PLL6M
            omw_set_sys_clk(SYS_CLK_PLL6M);
            omw_rtc_delay_ms(sys_dly);
            sys_t0 = omw_get_sys_clk();
            sys_t1 = omw_get_sys_clk_freq();
            printf("SYS_CLK mode: %d, freq: %d\n", sys_t0, sys_t1);
        }
    #endif

#ifdef OMW_FLASH_UID
    int i=0;
	uint8_t  omw_device_addr[6];
    omw_flash_get_device_addr(omw_device_addr);
    printf("omw_device_addr (hex): ");
	for(i=0;i<6;i++)
	{
	   printf("%02x ",omw_device_addr[i]);
	}
    printf("\n");
#endif

#ifdef OMW_CLKCAL
    // GPIO[7]: CLK_RC32K
    // GPIO[22]: CLK_RC24M
    omw_gpio_set_func(OMW_GPIO_PIN7, 0x06);
    omw_gpio_set_func(OMW_GPIO_PIN22, 0x06);
    printf("RC clk output setting finish\n");
    omw_clkcal_rc32k_calibration();
    printf("RC 32K: calibration finish\n");
    omw_clkcal_rc24m_calibration();
    printf("RC 24M: calibration finish\n");
#endif

	while(1);
    omw_flash_erase(0x10001000);  //page erase, 1 page, 256 byts, address must 256bytes aligned
    omw_flash_sector_erase(0x10001000);  //sector erase, 1 sector, 4KB, address must 4KB aligned

    uint8_t flash_data[] = "abcdefefdddddaagdkgldg";
    omw_flash_write(0x10001000, flash_data, sizeof(flash_data));  //address can be byte aligned

    // read flash must call omw_flash_read, can not use direct address access like:
    // memcpy(flash_data, (void *)0x10001001, 8)
    // because of cache
    omw_flash_read(0x10001001, flash_data, 9); //address can be byte aligned

    return 0;
}
