#include "user_sleep.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"
#include "soc/rtc.h"
#include "nvs_flash.h"
#include "nvs.h"
#include"EPD.h"
#include "FONT_LIB.h"
#include "esp_timer.h"
#include "freertos/timers.h"
#include "SPIFFS.h"

#include "ulp_main.h"

#include "LORA.h"


//定时器选择
#define   TIMER_CHOICE    1  //0:ESP  //1 FREERTOS


#if     TIMER_CHOICE

        TimerHandle_t sleep_timer;         //进入休眠定时器
        TimerHandle_t already_send_timer;  //可以发送数据的定时器
#else
        esp_timer_handle_t sleep_timer;         //开启睡眠定时器
        esp_timer_handle_t already_send_timer;  //可以发送数据的定时器
#endif


static RTC_DATA_ATTR struct timeval sleep_enter_time;


RTC_DATA_ATTR uint8_t _wakeup_reson = 0;  //内存上次唤醒的原因


int64_t sleep_before_us = 0;  //开始进入睡眠时间
int64_t sleep_afterr_us = 0;  //唤醒时间


#define DEEP_SLEEP 0

#if !DEEP_SLEEP

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_log.h"

static const char *LOG_TAG = "user_sleep";
extern QueueHandle_t sleep_queue;
extern QueueHandle_t wakeup_queue;

extern void light_sleep_task(void *args);
extern void wakeup_sleep_task(void *args);


bool is_sleep = false;




/*********************************************************************************
* function   :   sleep_timer_callback     
* Description :  进入睡眠回调函数
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void sleep_timer_callback(void* arg)
{
    #if 0
    send_sleep_Queue();
    #else
    //printf("fall into sleep\r\n");
    #include "ulp_riscv.h"
    #include "esp_sleep.h"
	#include "driver/uart.h"
    //printf("error =%d\r\n",err);
    sleep_before_us= esp_timer_get_time();
     uart_wait_tx_idle_polling(0);
     //ulp_riscv_timer_resume();

    is_sleep = true;

// #if LORA_SLEEP_ENABLE
//     //rtc_gpio_hold_dis(LORA_POWER_PIN);
//     lora_set_power_level(0);
//     //rtc_gpio_hold_en(LORA_POWER_PIN);
// #endif
//     esp_light_sleep_start();
    #endif
}


/*********************************************************************************
* function   :   sleep_timer_start     
* Description :  倒计时开始进入睡眠
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void sleep_timer_start(int ms)
{
#if     TIMER_CHOICE

        xTimerStop(sleep_timer, 0);   //停止定时器
        // 在这里可以改变定时器的超时时间
        // 第一个参数是定时器句柄，第二个参数是新的超时时间（以时钟节拍为单位）
        xTimerChangePeriod(sleep_timer, pdMS_TO_TICKS(ms), 0);

        xTimerStart(sleep_timer, 0); //开始定时器
 //xTimerStart(sleep_Timerout, 0);

#else

    #if 0
    ESP_ERROR_CHECK(esp_timer_start_once(sleep_timer, ms*1000));//500ms
    #else

    esp_timer_start_once(sleep_timer, ms*1000);//500ms
    #endif
#endif    
}

/*********************************************************************************
* function   :   sleep_timer_stop     
* Description :  停止进入睡眠
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void sleep_timer_stop(void)
{

#if     TIMER_CHOICE


     xTimerStop(sleep_timer, 0);   //停止定时器
#else
            #if 0
            ESP_ERROR_CHECK(esp_timer_stop(sleep_timer));
            #else
                esp_timer_stop(sleep_timer);
            #endif
#endif
}




//

/*********************************************************************************
* function   :   Already_send_timer_callback     
* Description :  定到达指定时间准备发送数据或者接收数据
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void Already_send_timer_callback(void* arg)
{
#if     TIMER_CHOICE

    //   printf("Already_send_timer_callback\r\n");

       extern void send_can_I_receive();

        if(Machine_info.eflagID != 0xff)
        {
                send_can_I_receive(); //发送可以接受的命令

                if(Send_list!=NULL)
                {
                    vTaskDelay(50 / portTICK_PERIOD_MS);
                    lora_send_data((char *)Send_list->data,Send_list->len);
                    printf("list have data send one data\r\n");
                }else
                {
                    printf("list not have data\r\n");
                }

        }
    //uart_wait_tx_idle_polling(UART_NUM_1);
    //example_register_timer_wakeup();
    //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US*Machine_info.eflagID);  //配置当前休眠的唤醒时间
    //printf("sleep time = %d\r\n",(TIMER_WAKEUP_TIME_US*Machine_info.eflagID)/1000);


    #if 1
       sleep_timer_start(1000);  //倒计时进入睡眠
    #endif   


#else

    #if 0
    send_sleep_Queue();
    #else
    printf("Already_send_timer_callback\r\n");

       extern void send_can_I_receive();
       send_can_I_receive(); //发送可以接受的命令
       uart_wait_tx_idle_polling(UART_NUM_1);

       sleep_timer_start(600);  //进入睡眠

    // #include "ulp_riscv.h"
    // #include "esp_sleep.h"
	// #include "driver/uart.h"
    // //printf("error =%d\r\n",err);
    //  uart_wait_tx_idle_polling(0);
    //  //ulp_riscv_timer_resume();
    // esp_light_sleep_start();
    #endif

 #endif   
}



/*********************************************************************************
* function   :   Already_send_timer_start     
* Description :  定到达指定时间准备发送数据或者接收数据
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void Already_send_timer_start(int ms)
{
    #if     TIMER_CHOICE
        xTimerStop(already_send_timer, 0);   //停止定时器
        // 在这里可以改变定时器的超时时间
        // 第一个参数是定时器句柄，第二个参数是新的超时时间（以时钟节拍为单位）
        xTimerChangePeriod(already_send_timer, pdMS_TO_TICKS(ms), 0);
        xTimerStart(already_send_timer, 0); //开始定时器
    #else
    ESP_ERROR_CHECK(esp_timer_start_once(already_send_timer, ms*1000));//500ms
    #endif
}

/*********************************************************************************
* function   :   Already_send_timer_stop     
* Description :  停止定时器
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void Already_send_timer_stop(void)
{

    #if     TIMER_CHOICE
     xTimerStop(already_send_timer, 0);   //停止定时器
    #else
    ESP_ERROR_CHECK(esp_timer_stop(already_send_timer));

    #endif
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*定时器唤醒*/
#include "esp_check.h"
#include "esp_sleep.h"



static const char *TAG = "timer_wakeup";

esp_err_t example_register_timer_wakeup(void)
{
    ESP_RETURN_ON_ERROR(esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US), TAG, "Configure timer as wakeup source failed");
    ESP_LOGI(TAG, "timer wakeup source is ready");
    return ESP_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif


void user_sleep_into()
{

    #if DEEP_SLEEP
    struct timeval now;
    gettimeofday(&now, NULL);
    int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;

    switch (esp_sleep_get_wakeup_cause()) {
#if CONFIG_EXAMPLE_EXT0_WAKEUP
        case ESP_SLEEP_WAKEUP_EXT0: {
            printf("Wake up from ext0\n");
            break;
        }
#endif // CONFIG_EXAMPLE_EXT0_WAKEUP
#ifdef CONFIG_EXAMPLE_EXT1_WAKEUP
        case ESP_SLEEP_WAKEUP_EXT1: {
            uint64_t wakeup_pin_mask = esp_sleep_get_ext1_wakeup_status();
            if (wakeup_pin_mask != 0) {
                int pin = __builtin_ffsll(wakeup_pin_mask) - 1;
                printf("Wake up from GPIO %d\n", pin);
            } else {
                printf("Wake up from GPIO\n");
            }
            break;
        }
#endif // CONFIG_EXAMPLE_EXT1_WAKEUP
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
        case ESP_SLEEP_WAKEUP_GPIO: {
            uint64_t wakeup_pin_mask = esp_sleep_get_gpio_wakeup_status();
            if (wakeup_pin_mask != 0) {
                int pin = __builtin_ffsll(wakeup_pin_mask) - 1;
                printf("Wake up from GPIO %d\n", pin);
            } else {
                printf("Wake up from GPIO\n");
            }
            break;
        }
#endif //SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
        case ESP_SLEEP_WAKEUP_TIMER: {
            printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms);
            break;
        }
#ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP
        case ESP_SLEEP_WAKEUP_TOUCHPAD: {
            printf("Wake up from touch on pad %d\n", esp_sleep_get_touchpad_wakeup_status());
            break;
        }
#endif // CONFIG_EXAMPLE_TOUCH_WAKEUP

        case ESP_SLEEP_WAKEUP_UNDEFINED:
        default:
            printf("Not a deep sleep reset\n");
    }

    vTaskDelay(1000 / portTICK_PERIOD_MS);

    const int wakeup_time_sec = 3;
    printf("Enabling timer wakeup, %ds\n", wakeup_time_sec);
    ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000));



    printf("Entering deep sleep\n");
    // get deep sleep enter time
    gettimeofday(&sleep_enter_time, NULL);

    font_into_sleep();

    #if 0 
    int i = 60;

    printf("not start deep display\r\n");
    while(i--)
    {
         vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    printf("start deep display\r\n");
    epd_sleep(SCREEN_LEFT);
    epd_sleep(SCREEN_RIGHT);
     i = 60;
       while(i--)
    {
         vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    #else
    epd_sleep(SCREEN_LEFT);
    epd_sleep(SCREEN_RIGHT);
    #endif
    // enter deep sleep
    esp_deep_sleep_start();
    #else



#if 0
    //进入睡眠timer
    const esp_timer_create_args_t lora_timer_args = {
            .callback = &sleep_timer_callback,
            /* argument specified here will be passed to timer callback function */
            .name = "sleep_one-shot"
    };
    ESP_ERROR_CHECK(esp_timer_create(&lora_timer_args, &sleep_timer));


    //唤醒后可以准备发送数据的timer
    const esp_timer_create_args_t send_timer_args = {
            .callback = &Already_send_timer_callback,
            /* argument specified here will be passed to timer callback function */
            .name = "sleep_one-shot"
    };
    ESP_ERROR_CHECK(esp_timer_create(&send_timer_args, &already_send_timer));
#else

 #if 1
     //创建
     sleep_timer = xTimerCreate(
         "sleep_timer",        // 定时器名称（可以为NULL）
         pdMS_TO_TICKS(800),         // 定时器超时时间（以毫秒为单位）
         pdFALSE,                    // 定时器为周期性（pdTRUE）还是单次（pdFALSE）
         0,                          // 定时器ID（可以为0）
         sleep_timer_callback  // 定时器回调函数
     );




    //创建
     already_send_timer = xTimerCreate(
         "already_send_timer",        // 定时器名称（可以为NULL）
         pdMS_TO_TICKS(800),         // 定时器超时时间（以毫秒为单位）
         pdFALSE,                    // 定时器为周期性（pdTRUE）还是单次（pdFALSE）
         0,                          // 定时器ID（可以为0）
         Already_send_timer_callback  // 定时器回调函数
     );

 //xTimerStart(sleep_Timerout, 0);
 #else
 sleep_timer_start(5000);


 #endif



#endif





   #endif

}





int is_wake_up_reson()  //返回唤醒的原因
{
    _wakeup_reson  = esp_sleep_get_wakeup_cause();
    // /* not a wakeup from ULP, load the firmware */
    // if ((cause != ESP_SLEEP_WAKEUP_ULP) && (cause != ESP_SLEEP_WAKEUP_TIMER)) {
    //     printf("Not a ULP-RISC-V wakeup (cause = %d), initializing it! \n", cause);
    //     init_ulp_program();
    // }
    return _wakeup_reson;
}

#include "user_button.h"

int left_adc_wake_btn_send()
{


uint16_t adc_value[][2]=
{
    {BAOYANG_MIN_ADC,BAOYANG_MAX_ADC},
    {FENGCUN_MIN_ADC,FENGCUN_MAX_ADC},
    {GUZHUANG_MIN_ADC,GUZHANG_MAX_ADC},
    {DAILIAO_MIN_ADC,DAILIAO_MAX_ADC},
    {TINGJI_MIN_ADC,TINGJI_MAX_ADC},
    {YUNXING_MIN_ADC,YUNXING_MAX_ADC},
};


     //获取adc值 返回左界面索引值
    #include "user_button.h"

    int result = 0xff;

    int button_info = 0xfB;

     //extern uint16_t adc_value[][2];

        #include "ulp/example_config.h"
        // extern int32_t wakeup_result;
        // int result_adc = wakeup_result;
        #if 1
        int result_adc = ulp_wakeup_result;

        #endif

        int mid_result  = result_adc ;//(int)(((float)(result_adc/4095.0))*1100);

        printf("mid adc = %d\r\n",mid_result);
        for(int i = 0;i<6;i++)
        {
            if( ( adc_value[i][0]<=mid_result) &&   ( adc_value[i][1]>=mid_result)   )
            {
                    result =  i;
                    break;
            }
        }





         switch ((int)result)
    {
    case BAOYANG_KEY:
            button_info = 6;
            //ESP_LOGD(LOG_TAG,"bao yang");
        break;
    case FENGCUN_KEY:
            button_info = 5;
            //ESP_LOGD(LOG_TAG,"feng cun");
        break;
    case GUZHUANG_KEY:
            button_info = 4;
            //ESP_LOGD(LOG_TAG,"gu zhang");
        break;
    case DAILIAO_KEY:
            button_info = 3;
            //ESP_LOGD(LOG_TAG,"dai liao");
        break;
    case TINGJI_KEY:
            button_info = 2;
            //ESP_LOGD(LOG_TAG,"ting ji");
        break;
    case YUNXING_KEY:
            button_info = 1;
            //ESP_LOGD(LOG_TAG,"yun xing");
        break;
    default:
        break;
    }


    ulp_wakeup_result = 3300;


    if(button_info>6)
    {
        return 0xff;
    }
       


    return button_info;
             
}