#include "omw_config.h"
#include "omw_dbg.h"
#include "omw_svc.h"
#include "data_xfer.h"
#include "utils/sys_timer.h"
#include "periph_gpadc.h"
#include <limits.h>

#ifdef OMW_EN_CARR_MODE
static uint8_t st_carr;
static uint8_t carr_ch = 12;

extern void omw_rf_start_carrier_mode(uint8_t ch);
extern void omw_rf_stop_carrier_mode();

void omw_app_init_after_ble_init()
{
    while(1)
    {
        if (!st_carr)
        {
            omw_rf_start_carrier_mode(carr_ch);
            st_carr = 1;
        }
    }
}
#else
static uint8_t  app_can_sleep;

static uint8_t  tx_buf[] = {0xAB, 0x11, 0xCD, 0x22, 0x33, 0xEF, 0x88, 0x66};
static const omw_svc_info_t * p_dx_svc;
uint32_t  deft_conn = 0;
//when connected, this function will be called
void omw_app_connected_cb(uint32_t conn_handle, uint16_t cintlv, uint16_t cintlv_min, uint16_t cintlv_max)
{
    deft_conn = conn_handle;
    app_can_sleep = 0;
}

//when dis-connected, this function will be called
void omw_app_disconnected_cb(uint32_t conn_handle, uint8_t reason)
{
    deft_conn = 0;
    app_can_sleep = 1;
}

//when rcv data, this function will be called
void omw_app_rx_process_cb(const uint8_t * buf, uint16_t len)
{
    //for example, loop back:
    p_dx_svc->nt_tx_cb(deft_conn, buf, len);
}

const uint8_t * omw_app_read_usr_data_cb(uint16_t * len)
{
    *len = sizeof(tx_buf);
    return tx_buf;
}

#ifdef OMW_EN_SLEEP_TMR_CHK
#define USER_DEF_SLEEP_ELPS  (2 * 1000 * 1000)  //2s
static uint32_t app_last_sleep_chk;
extern uint8_t need_pwr_on;
__RAM_CODE_SECTION
void omw_app_sleep_process()
{
    uint32_t cur_ticks = REG_RD(0x42000104);
    if (app_last_sleep_chk == 0)
    {
        app_last_sleep_chk = cur_ticks;
        return;
    }

    if ((uint32_t)(cur_ticks - app_last_sleep_chk) > USER_DEF_SLEEP_ELPS)
    {
        app_last_sleep_chk = cur_ticks;
        need_pwr_on = 1;
    }
}
#endif

void omw_flash_get_device_addr(uint8_t *dev_addr);
//run one time
void omw_app_init()
{
    uint8_t  new_addr[] = {0x34, 0x45, 0xA2, 0x98, 0x15, 0x20};
    omw_svc_set_addr(new_addr);

    app_can_sleep = 1;

    p_dx_svc = omw_data_xfer_svc_get_svc_info();
    p_dx_svc->xfer_reg_cb(omw_app_rx_process_cb, omw_app_read_usr_data_cb);

    /* call omw_svc_start_svc_adv will adv auto, not need to setting more adv/scan rsp params */
    /* if only call omw_svc_add_svc, will not adv auto, you need to call omw_svc_start_adv to start adv */
    /* for example:
        omw_svc_add_svc(svc1);
        omw_svc_add_svc(svc2);

        omw_svc_set_adv_intvl(10, 20);
        omw_set_adv_data(adv_data, 10);
        omw_set_scan_rsp_data(scr_data, 20);

        omw_svc_start_adv();
    */
    omw_svc_start_svc_adv(p_dx_svc);
}

#ifdef OMW_EN_ADC_DEMO
uint8_t adc_init_flag;
void adc_init(void){
    //当与BLE或2.4G一起工作时，初始化时不能调用GPADC_LDOInit
    //当作为独立的ADC程序工作时，初始化时必须调用GPADC_LDOInit
    // GPADC_LDOInit();

    GPADC_StartCalibration();

    GPADC_InitTypeDef GPADC_InitStruct;
    GPADC_StructInit(&GPADC_InitStruct);

    GPADC_InitStruct.GPADC_InputDivide = GPADC_INPUT_DIV1;
    GPADC_InitStruct.GPADC_DiffEN = DISABLE;
    GPADC_InitStruct.GPADC_PositiveInputChannel = GPADC_CHANNEL_GPIO2;
    GPADC_InitStruct.GPADC_AverageWindow = GPADC_AVG_NUM_128;
    GPADC_InitStruct.GPADC_ContinueMode = DISABLE;

    GPADC_Init(&GPADC_InitStruct);
    GPADC_Cmd(ENABLE); // enable

    adc_init_flag = 1;
}
#endif

//run one time after ble base init
void omw_app_init_after_ble_init()
{
}

//called after wake_up from deep-sleep
void omw_app_main_after_wake_up()
{

}

#ifdef OMW_EN_ADC_DEMO
#ifndef APP_GPADC_1
static uint8_t   app_gpadc_st;
#endif

uint8_t vbat_up_cnt;
uint8_t pending_adc_flag;
#endif

//called by sleep module, check if system can goto sleep
uint8_t omw_app_can_sleep()
{
    #ifdef OMW_EN_ADC_DEMO
    #ifndef APP_GPADC_1
    if (app_gpadc_st || pending_adc_flag) return 0;
    #endif
    #endif

    return app_can_sleep;
}

#define DFT_SLP_CNT_MIN_INTVL   80     //DFT_SLP_CNT_MIN_INTVL*1.25ms
#define DFT_SLP_CNT_MAX_INTVL   80     //DFT_SLP_CNT_MAX_INTVL*1.25ms
#define DFT_SLP_LT              0      //DFT_SLP_LT
#define DFT_SLP_TO              1000    //DFT_SLP_TO ms

#ifdef OMW_EN_ADC_DEMO
#define ADC_NEED_TM_MS   40
static uint32_t  app_last_gpadc_time;
uint8_t omw_set_gpadc_busy(uint8_t busy, uint16_t need_tm_ms);


void omw_app_start_gpadc()
{
    uint32_t cur_ticks = REG_RD(0x42000104);

    #ifdef APP_GPADC_1
    if (cur_ticks - app_last_gpadc_time > USER_DEF_SLEEP_ELPS)
    {
        if (omw_set_gpadc_busy(1, ADC_NEED_TM_MS))
        {
            ///////////START///////////////
            //TODO: start gpadc/temp test
            // while(1)
            // {
            //     //all done: break;
            // }
            /////////////END////////////////
            omw_set_gpadc_busy(0, 0);
            app_last_gpadc_time = cur_ticks;
        }
    }
    #else
    if (!app_gpadc_st)
    {
        if (cur_ticks - app_last_gpadc_time > USER_DEF_SLEEP_ELPS)
        {
            uint32_t vbat, vio;

            pending_adc_flag = 1;

            ////////////////Start one channel test////////////////////////
            //if (!omw_svc_can_use_gpadc()) return;
            if (omw_set_gpadc_busy(1, ADC_NEED_TM_MS))
            {
                if (!adc_init_flag)
                {
                    adc_init();
                }

                pending_adc_flag = 0;
                app_gpadc_st = 1;

                // uint32_t bf_tm = REG_RD(0x42000104);
                if (!(vbat_up_cnt & 15)) //DEMO, 16 * 2 = 32秒做一次电压电压校准
                {
                    // 获取电源电压用做校准, 电压短时间变化不大，则不用在做GPADC时进行测试校准，周期可拉长。
                    GPADC_BATUpdate(); //防止长时间运行电池电压下降，周期性调用这个函数更新电池电压用做校准
                    vbat_up_cnt = 0;
                }

                vbat_up_cnt++;

                vbat = g_gpadc_vbat;

                // 获取电源电压
                // GPADC_ChangeChannel(GPADC_CHANNEL_BAT);
                // vbat = GPADC_SampleVoltagePoll(); // 0 ~ 3500 mV

                // 获取IO电压
                //GPADC_ChangeChannel(GPADC_CHANNEL_GPIO2);
                vio = GPADC_SampleVoltagePoll(); // 100 mV ~ 2800 mV

                // uint32_t epls_tm = REG_RD(0x42000104) - bf_tm;
                // printf("adc elps tm : %d\n", (int)epls_tm);

                omw_set_gpadc_busy(0, 0);
                /////////////One channel finished/////////////////////

                printf("  -> vbat: %4d mV, vntc: %4d mV\r\n", (int)vbat, (int)vio);
            }
        }
    }
    else
    {
        //if (previous test finished)
        {
            //if (has next channel test)
            {
                //TODO: Start Next channel test
            }
            //else if (all done)
            {
                app_gpadc_st = 0;
                app_last_gpadc_time = cur_ticks;
            }
        }
    }
    #endif
}
#endif

uint16_t T1001_WakeupSource(void);
uint32_t  counter = 0;
//run every time in main loop
//NOTICE: DO NOT USE INFINITE LOOP in app_main(). DO NOT DELAY LONG TIME in app_main()
//You can use timer to process periodic bussiness
void omw_app_main()
{
    if (T1001_WakeupSource())
    {//wake up from deep sleep
        #ifdef OMW_EN_ADC_DEMO
        adc_init_flag = 0;
        #endif

        printf("wake up fully!\n");
    }

    #ifdef OMW_EN_ADC_DEMO
    omw_app_start_gpadc();
    #endif

    counter++;

    if (deft_conn)
    {
        struct bt_conn_info info;
        bt_conn_get_info((struct bt_conn *)deft_conn, &info);

        if (info.le.interval < DFT_SLP_CNT_MIN_INTVL)
        {
            app_can_sleep = 0;

            if ((counter & 0xFFFF) == 0)
            {
                int err = omw_svc_updata_cnnt_param(deft_conn, DFT_SLP_CNT_MIN_INTVL, DFT_SLP_CNT_MAX_INTVL, 0, DFT_SLP_TO);

                if (err)
                {
                    // printf("conn update failed (err %d).\n", err);
                }
            }
        }
        else
        {
//            app_can_sleep = 1;//Comments at test
        }
    }
}
#endif
