#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/event_groups.h"
#include "esp_timer.h"
#include "esp_err.h"

#include "user_config.h"

//#include "lvgl/lvgl.h"
#include"LED.h"
#include"list.h"
#include "freertos/timers.h"

#include "user_sleep.h"
#include "esp_sleep.h"
#include "esp_sleep.h"
//#include "ble_ota.h"

#include "batt_charge.h"
#include "user_time.h"
#include "driver/uart.h"
#include "driver/rtc_io.h"


char user_device_id[50] ={0}; 


RTC_FAST_ATTR unsigned char power = 0;



#define MAX_RETRY_ACK   3   //最大重传次数停止发送数据
int retry_times = 0;
bool powerOn_flag = false;
static const char *LOG_TAG = "user_main";

extern Node *Send_list;  //发送数据链表

YC_DATA_T yc_data;

//ListNode *list_head = NULL;

adc_oneshot_unit_handle_t adc1_handle;
QueueHandle_t left_screen_queue;
QueueHandle_t right_screen_queue;
QueueHandle_t lora_data_queue;
QueueHandle_t yc_data_queue;
QueueHandle_t button_Data_queue;
EventGroupHandle_t screen_event;

extern QueueHandle_t lora_receiveQueue; //lora底层数据上报

extern QueueHandle_t lora_dealhandle;  //开始处理逻辑的数据



QueueHandle_t sleep_queue;
QueueHandle_t wakeup_queue;

QueueHandle_t Send_Data_queue;  //发送链表任务

SemaphoreHandle_t button_semaphore;        //刷新屏幕时都得加上按键互斥锁

SemaphoreHandle_t screen_semaphore;  //刷新屏幕时都得加上互斥锁



#if !HARDWARE_SPI
struct EPD_INFO_SET left_screen = {};
struct EPD_INFO_SET right_screen = {};
#endif


extern LORA_DATA_T lora_data;
extern TERMINAL_INFO_T terminal_info;

#include "y_ringbuf.h"
extern struct RINGBUF_st;
extern RINGBUF_st *lora_ringbuf;

// static void board_init(void);
// static void info_init(void);

static void left_screen_task(void* arg);
static void right_screen_task(void* arg);
static void unpack_task(void* arg);
static void lora_task(void* arg);
static void button_task(void* arg);
static void business_logic_task(void* arg);
static void gui_task(void* pvParameter);

void read_deal_data_callback_handler();
// void Sendlist_task_callback_handler();

void uart_task_callback_handler();




void beep_open()
{

            // Set duty to 50%
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));


}


void beep_close()
{
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

}


void beep_blink(uint16_t ms,uint16_t count)
{

    for(int i =0;i<count;i++)
    {
        //printf("beep\r\n");
        beep_open();
        vTaskDelay(ms / portTICK_PERIOD_MS);
        beep_close();
        vTaskDelay(ms / portTICK_PERIOD_MS);
    }
 
}




/*********************************************************************************
* function   :   user_nvs_init     
* Description :  添加NVS相关 获取出厂设备ID等相关参数
* Input       :  
* Output      :  
* Author      :                      Data : 2023 11.08
**********************************************************************************/	
void user_nvs_init()
{
    #include "nvs_flash.h"
    #include "nvs.h"
    nvs_handle_t my_handle;

    esp_err_t ret;
    /* Initialize NVS. */
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
        printf("nvs_flash_init ok\r\n");
    }

     ret = ESP_OK;
    if ((ret = nvs_flash_init_partition("nvs")) != ESP_OK)
    {
            printf("nvs init fail\r\n");
    }else
    {
            printf("nvs init ok\r\n");
    }


    ret = nvs_open_from_partition("nvs", "user_config", NVS_READONLY, &my_handle);

    if (ret != ESP_OK) {
        printf("nvs_open failed with\r\n");
    }

size_t len = 0;
char cid[50] ={0};

//size_t required_size;
//nvs_get_str(my_handle, "server_name", NULL, &required_size);
//char* server_name = malloc(required_size);
//nvs_get_str(my_handle, "server_name", server_name, &required_size);


ret = nvs_get_str(my_handle,"deviceid",NULL,&len);

char* result = malloc(len);
nvs_get_str(my_handle, "deviceid", result, &len);


switch (ret) {
            case ESP_OK:
                //printf("Read string from NVS: %s\r\n", cid);
                break;
            case ESP_ERR_NVS_NOT_FOUND:
                printf( "Value not found in NVS");
                break;
            default:
                printf("Error (%d) reading from NVS", ret);
        }

    memcpy(user_device_id,cid,len);

    memcpy(Machine_info.cid,cid,len);
    

    strcpy((char *)Machine_info.cid,result);
    printf("device id %s,result = %s,len = %d\r\n",cid,result,len);

    printf("Machine_info cid %s\r\n",Machine_info.cid);
    nvs_close(my_handle);


    free(result);

}









extern void app_init();



     Machine_info_t default_info={
            .left_display_mode = 0,
            .left_state = 1,
            .paired = 0,        //未配网
            .power_status = 0,  //关机
            // .is_setting = 0,     //设置模式
            .eflagID = 0xFF,
            .left_max_Quick_refresh_time = 5,    //最大快刷次数
            .left_current_Quick_refresh_time = 0,//当前已经快刷的次数  当前快刷的次数大于设置 慢刷一次
            .lora_factory_channel = LORA_CHANENL,
            .right_max_Quick_refresh_time = 5,    //最大快刷次数
            .right_current_Quick_refresh_time = 0,//当前已经快刷的次数  当前快刷的次数大于设置 慢刷一次

            .current_button.button_info = 0x01, //初始化为1（运行）
            .last_button.button_info    = 0x01,
            .terminal_name = {0xD2,0xCF,0xB3,0xB2,0xD6,0xD5,0xB6,0xCB,0x00,0x00},//蚁巢终端
            .terminal_number = {0xD2,0xCF,0xB3,0xB2,0xB1,0xE0,0xBA,0xC5,0x00,0x00},//蚁巢编号
            .station_name = {0xB9,0xA4,0xD5,0xBE,0xC3,0xFB,0xB3,0xC6,0x00,0x00},//工站名称
            .station_number = {0xB9,0xA4,0xD5,0xBE,0xB1,0xE0,0xBA,0xC5,0x00,0x00},//工站编号
            .rssi = 0x64,
            .refresh_cycle = 2,
            .batt_precent = 100,
            .btn_operation = {0xd4,0xcb,0xd0,0xd0,0x00,0x00},
            .btn_breakDown_info = {0xb9,0xca,0xd5,0xcf,0x00,0x00},
            .btn_shutDown_info = {0xcd,0xa3,0xbb,0xfa,0x00,0x00},
            .btn_safeKeep_info = {0xb7,0xe2,0xb4,0xe6,0x00,0x00},
            .btn_upKeep_info = {0xb1,0xa3,0xd1,0xf8,0x00,0x00},
            .btn_waitMaterials_info = {0xb4,0xfd,0xc1,0xcf,0x00,0x00},
            .btn_dis_flag = {true,true,true,true,true,true},
            .checkIn_set[0] ={
                .other_name = {0xC9,0xFA,0xB2,0xFA,0x00,0x00},
                .checkIn_close = false,
            },
            .checkIn_set[1] ={
                .other_name = {0xCE,0xAC,0xD0,0xDE,0x00,0x00},
                .checkIn_close = false,
            },
            .checkIn_set[2] ={
                .other_name = {0xD1,0xB2,0xBC,0xEC,0x00,0x00},
                .checkIn_close = false,
            },
            .checkIn_set[3] ={
                .other_name = {0xB1,0xA3,0xD1,0xF8,0x00,0x00},
                .checkIn_close = false,
            },
            .person[0] = {
                .Charge_close = false,
                .other_name = {0xb9,0xdc,0x20,0x20,0xc0,0xed,0x20,0x20,0xd4,0xb1,0x3a,0x00,0x00,0x00},
            },
            .person[1] = {
                .Charge_close = false,
                .other_name = {0xc9,0xfa,0xb2,0xfa,0xd4,0xf0,0xc8,0xce,0xc8,0xcb,0x3a,0x00,0x00,0x00},
            },
            .person[2] = {
                .Charge_close = false,
                .other_name = {0xce,0xac,0xd0,0xde,0xd4,0xf0,0xc8,0xce,0xc8,0xcb,0x3a,0x00,0x00,0x00},
            },
            .person[3] = {
                .Charge_close = false,
                .other_name = {0xb1,0xa3,0xd1,0xf8,0xd4,0xf0,0xc8,0xce,0xc8,0xcb,0x3a,0x00,0x00,0x00},
            },
            .person[4] = {
                .Charge_close = false,
                .other_name = {0xd1,0xb2,0xbc,0xec,0xd4,0xf0,0xc8,0xce,0xc8,0xcb,0x3a,0x00,0x00,0x00},
            },
        };

#define PRINT_SPIFFS 0
#if PRINT_SPIFFS

void printHexData(const void *ptr, size_t size) {
    const unsigned char *p = (const unsigned char *)ptr;
    for (size_t i = 0; i < size; ++i) {
        printf("%02x ", p[i]);
            if(i%16 == 0)
        {
            printf("\r\n");
        }
    }
    //printf("\n");
}
#endif


void app_init()
{

#if 0
        gpio_reset_pin(4);
        gpio_config_t io_conf = {};
        io_conf.pin_bit_mask = (1<<4);
        io_conf.mode = GPIO_MODE_INPUT;
        io_conf.pull_up_en = false;
        gpio_config(&io_conf);

    while(1)
    {

         printf("power gpio is %s\r\n",gpio_get_level(4)?"high":"low"); 
         vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    #endif
//设置蜂鸣器声音
#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
    led_init();
#endif


#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
   font_init();
#endif

#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
    epd_init();
#endif

    user_sleep_into(); //休眠定时器初始化
//charge_init();
//decection_charging_init();

    left_screen_queue   =   xQueueCreate(10, sizeof(Machine_info_t));
    right_screen_queue  =   xQueueCreate(10, sizeof(Machine_info_t));

    lora_data_queue     =   xQueueCreate(20, sizeof(LORA_DATA_T));

    yc_data_queue       =   xQueueCreate(20, sizeof(int));

    button_Data_queue   =   xQueueCreate(10, sizeof(uint8_t));

    screen_semaphore    =   xSemaphoreCreateMutex();
    screen_event = xEventGroupCreate();
// button_semaphore    =   xSemaphoreCreateMutex();





#if 0
lora_receiveQueue = xQueueCreate(100, sizeof(int));
#else
lora_dealhandle  = xQueueCreate(100, sizeof(int));
#endif

sleep_queue  = xQueueCreate(10, sizeof(uint8_t));

// Send_Data_queue= xQueueCreate(10, sizeof(uint8_t));  //发送缓存数据任务

if (sleep_queue != NULL) {
    // 创建队列成功，myQueue 包含有效的队列句柄
    // 在这里可以继续使用该队列
} else {
    // 创建队列失败，myQueue 是 NULL
    // 需要处理创建失败的情况
	printf("---------------create fail-----------------\r\n");
}




 wakeup_queue = xQueueCreate(10, sizeof(uint8_t));


if (wakeup_queue != NULL) {
    // 创建队列成功，myQueue 包含有效的队列句柄
    // 在这里可以继续使用该队列
} else {
    // 创建队列失败，myQueue 是 NULL
    // 需要处理创建失败的情况
	printf("---------------create fail-----------------\r\n");
}


    extern unsigned char *last_paint_buf_left;
    extern unsigned char *last_paint_buf_right;
    extern uint32_t display_size;


#if 0
extern unsigned char *tmp_paint_buf;

tmp_paint_buf = heap_caps_malloc(display_size,MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);  // 开辟 结构体句柄 所需要的空间

if(tmp_paint_buf!=NULL)
{
    //printf("tmp_paint_buf malloc success\r\n");
}else
{
    printf("tmp_paint_buf malloc fail\r\n");
    heap_caps_free(tmp_paint_buf);
}
#endif

#if 1
    last_paint_buf_left = heap_caps_malloc(display_size,MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);  // 开辟所需要的空间

if(last_paint_buf_left!=NULL)
{
    //printf("last_paint_buf_left malloc success\r\n");
}else
{
    printf("last_paint_buf_left malloc fail\r\n");
    heap_caps_free(last_paint_buf_left);
}

last_paint_buf_right = heap_caps_malloc(display_size,MALLOC_CAP_8BIT|MALLOC_CAP_SPIRAM);  // 开辟所需要的空间

if(last_paint_buf_right!=NULL)
{
    //printf("last_paint_buf_right malloc success\r\n");
}else
{
    printf("last_paint_buf_right malloc fail\r\n");
    heap_caps_free(last_paint_buf_right);
}
#endif





  int reson = esp_sleep_get_wakeup_cause(); //获取当前唤醒原因


    if(reson == ESP_SLEEP_WAKEUP_EXT1)
    {

        adc1_init();
        extern void dis_right_instructions();
        dis_right_instructions();
        
        int power_key  = 0; 
        int charge_key = 0; 

        int value_count = 0;



        charge_key = gpio_get_level(2);
        printf("charge_key is %s\r\n",!charge_key?"charge in":"charge out");
        printf("charge_key is %s\r\n",!charge_key?"charge in":"charge out");
        printf("charge_key is %s\r\n",!charge_key?"charge in":"charge out");
        printf("charge_key is %s\r\n",!charge_key?"charge in":"charge out");


            Machine_info.batt_precent =  read_battery_voltage();

            Machine_info.last_batt_precent = Machine_info.batt_precent;  

        while(1)
        {
            //value++;
            charge_key = gpio_get_level(2);

            if(!charge_key)  //充电中
            {

                Machine_info.batt_precent =  read_battery_voltage();

                if(Machine_info.batt_precent <96)
                {   
                        user_compare_power_off(Machine_info.last_batt_precent,Machine_info.batt_precent);
                        printf("charge_key is %s,batt=%d,last batt=%d\r\n",!charge_key?"charge in":"charge out",Machine_info.batt_precent,Machine_info.last_batt_precent);
                        
                        value_count++;

                if(value_count>60)
                {
                    Machine_info.last_batt_precent = Machine_info.batt_precent;
                    value_count = 0;
                }

                            #if 0
                            power_key = gpio_get_level(4);

                    vTaskDelay(4000 / portTICK_PERIOD_MS);
                    
                    if( 0  == gpio_get_level(4))
                    {
                        uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
                        printf("power on\r\n");

                                #if 1//USER_DEEP_SLEEP_ENABLE
                                reson  = is_wake_up_reson();  //返回唤醒的原因
                                /* ULP Risc-V read and detected a temperature above the limit */
                                if (reson == ESP_SLEEP_WAKEUP_EXT0)
                                {

                                    if(Machine_info.power_status == 0)
                                    {
                                        Machine_info.power_status  = 1; //开机


                                        lora_set_power_level(1); //打开lora电源




                                        

                                                // Set duty to 50%
                                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                                        // Update duty to apply the new value
                                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                                        vTaskDelay(1000/ portTICK_PERIOD_MS);

                                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                                        // Update duty to apply the new value
                                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                                        Machine_info.left_current_Quick_refresh_time = 5;
                                        vTaskDelay(1000/ portTICK_PERIOD_MS);

                                        if(xQueueSend(left_screen_queue,&Machine_info,portMAX_DELAY) != true)
                                        {
                                            printf("left send fail\r\n");
                                        } 

                                        }else if(Machine_info.power_status == 1)
                                        {
                                            printf("aready power on\r\n");

                                        }
                                    
                                }
                                #endif



                                break;
                            }
                            #endif

                }

            }else            //未充电
            {
                printf("charge_key is %s\r\n",!charge_key?"charge in":"charge out");

                extern void dis_right_instructions();
                dis_right_instructions();




                        
                printf("start power off\r\n");
                uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);

                
                #if 1           //电源按键
                 // adc_oneshot_del_unit(adc1_handle);
                gpio_reset_pin(4);
                int ext_wakeup_pin_0 = 4;
                printf("Enabling EXT0 wakeup on pin GPIO%d\n", ext_wakeup_pin_0);
                ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(ext_wakeup_pin_0, 0));

                // Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
                // EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
                // No need to keep that power domain explicitly, unlike EXT1.
                ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_0));
                ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_0));


                gpio_reset_pin(2);
                const int ext_wakeup_pin_1 = 2;
                const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
                printf("Enabling EXT1 wakeup on pins GPIO%d\r\n",ext_wakeup_pin_1);
                ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW));

                #endif
                esp_deep_sleep_start();
                
                break;
            }

            vTaskDelay(1000 / portTICK_PERIOD_MS);
            
            
        }

        
}


xTaskCreate( left_screen_task, "left_screen_task", 25*1024, NULL, configMAX_PRIORITIES - 1, NULL);




//idf.py 设置分区
spiffs_init();

extern uint32_t ulp_wakeup_result;



  if
  (
    (reson !=ESP_SLEEP_WAKEUP_EXT0)&&
    (reson !=ESP_SLEEP_WAKEUP_ULP)&&
    (reson !=ESP_SLEEP_WAKEUP_TIMER) 
  )
  {
          
            #if PRINT_SPIFFS
            printHexData(&default_info,sizeof(Machine_info_t));
            // spiffs_write(&default_info);
            #endif

            spiffs_read_powerOn(&Machine_info);


            //重新初始化开机后默认关机
            Machine_info.power_status = 0;



            user_nvs_init();
  }





    if(reson == ESP_SLEEP_WAKEUP_EXT0)
    {

        #if 0
        adc1_init();
        int value = 0;
        while(1)
        {
            value++;
            adc_read_left_key_pin(adc1_handle);
            vTaskDelay(10 / portTICK_PERIOD_MS);
            if(value>10)
            {
                break;
            }
        }
        #else
        int power_key =0; 

        adc1_init();
         while(1)
        {
            //value++;
            power_key = gpio_get_level(4);

            vTaskDelay(4000 / portTICK_PERIOD_MS);
              
            if( 0  == gpio_get_level(4))
            {
            
            
            
                        if(read_battery_voltage()<10)    //判断电压小于10% 不让开机
                    {


                            printf("start power off\r\n");
                            uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);

                            #if 1           //电源按键
                            // adc_oneshot_del_unit(adc1_handle);
                            gpio_reset_pin(4);
                            int ext_wakeup_pin_0 = 4;
                            printf("Enabling EXT0 wakeup on pin GPIO%d\n", ext_wakeup_pin_0);
                            ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(ext_wakeup_pin_0, 0));

                            // Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
                            // EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
                            // No need to keep that power domain explicitly, unlike EXT1.
                            ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_0));
                            ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_0));


                            gpio_reset_pin(2);
                            const int ext_wakeup_pin_1 = 2;
                            const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
                            printf("Enabling EXT1 wakeup on pins GPIO%d\r\n",ext_wakeup_pin_1);
                            ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW));

                            #endif
                            esp_deep_sleep_start();

                    }


                adc_oneshot_del_unit(adc1_handle);  //删除adc使用
                uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
                printf("power on-\r\n");

#if 1//USER_DEEP_SLEEP_ENABLE
                reson  = is_wake_up_reson();  //返回唤醒的原因
                /* ULP Risc-V read and detected a temperature above the limit */
                if (reson == ESP_SLEEP_WAKEUP_EXT0)
                {
                    if(Machine_info.power_status == 0)
                    {
                        Machine_info.power_status  = 1; //开机
                        lora_set_power_level(1); //打开lora电源
                                // Set duty to 50%
                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                        // Update duty to apply the new value
                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                        vTaskDelay(1000/ portTICK_PERIOD_MS);

                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                        // Update duty to apply the new value
                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                        Machine_info.left_current_Quick_refresh_time = 5;
                        vTaskDelay(1000/ portTICK_PERIOD_MS);
                        printf("开机刷屏\r\n");
                        if(xQueueSend(left_screen_queue,&Machine_info,portMAX_DELAY) != true)
                        {
                            printf("left send fail\r\n");
                        }
                    }else if(Machine_info.power_status == 1){
                        printf("aready power on\r\n");
                    }
                }
#endif
                break;
            }else
            {
                      
                printf("start power off\r\n");
                uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);

                
                #if 1           //电源按键
                 // adc_oneshot_del_unit(adc1_handle);
                gpio_reset_pin(4);
                int ext_wakeup_pin_0 = 4;
                printf("Enabling EXT0 wakeup on pin GPIO%d\n", ext_wakeup_pin_0);
                ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(ext_wakeup_pin_0, 0));

                // Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
                // EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
                // No need to keep that power domain explicitly, unlike EXT1.
                ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_0));
                ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_0));


                gpio_reset_pin(2);
                const int ext_wakeup_pin_1 = 2;
                const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
                printf("Enabling EXT1 wakeup on pins GPIO%d\r\n",ext_wakeup_pin_1);
                ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW));

                #endif
                esp_deep_sleep_start();
            }
        }


        #endif


        printf("deep Wake up from ext0\n");
        
    
    }else if(reson == ESP_SLEEP_WAKEUP_ULP)
    {
        printf("wakeup_result = %ld\r\n",ulp_wakeup_result);       

      
        // int key = find_key_value(ulp_wakeup_result);
        
        // printf("key = %d\r\n",key);     

        #if 1
     //reson  = is_wake_up_reson();  //返回唤醒的原因
    /* ULP Risc-V read and detected a temperature above the limit */
    if (reson == ESP_SLEEP_WAKEUP_ULP) 
    {

             if(Machine_info.power_status == 0)
            {
                printf("left key press power off\r\n");
                uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);

                #if 1    






                              font_into_sleep();
                                #include "EPD.h"
                                epd_sleep(SCREEN_LEFT);
                                epd_sleep(SCREEN_RIGHT);

                                //gpio_hold_en(PIN_L_CS);
                                //gpio_hold_en(PIN_R_CS);

                                // gpio_set_level(PIN_L_CS,1);
                                // gpio_set_level(PIN_R_CS,1);
                                //gpio_reset_pin(46);

                               
                                //uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
                                //ESP_ERROR_CHECK(uart_wait_tx_done(UART_NUM_1,portMAX_DELAY));
                                esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);

                                // gpio_set_level(LORA_TXD_PIN, 0);
                                // gpio_set_level(LORA_RXD_PIN, 0);

                                //uart_sleep_in_config();
                                uart_driver_delete(UART_NUM_1);
                                gpio_reset_pin(LORA_TXD_PIN);
                                gpio_reset_pin(LORA_RXD_PIN);

                                gpio_config_t io_conf = {};
                                io_conf.pin_bit_mask = (1<<LORA_TXD_PIN);
                                io_conf.mode = GPIO_MODE_OUTPUT;
                                io_conf.pull_up_en = false;
                                gpio_config(&io_conf);

                                io_conf.pin_bit_mask = (1<<LORA_RXD_PIN);
                                io_conf.mode = GPIO_MODE_OUTPUT;
                                io_conf.pull_up_en = false;
                                gpio_config(&io_conf);
                            
                                gpio_set_level(LORA_TXD_PIN, 0);
                                gpio_set_level(LORA_RXD_PIN, 0);
                                gpio_hold_en(LORA_TXD_PIN);
                                gpio_hold_en(LORA_RXD_PIN);
                
                
                
                
                  //电源按键
                 // adc_oneshot_del_unit(adc1_handle);
                gpio_reset_pin(4);
                int ext_wakeup_pin_0 = 4;
                //printf("Enabling EXT0 wakeup on pin GPIO%d\n", ext_wakeup_pin_0);
                ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(ext_wakeup_pin_0, 0));

                // Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
                // EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
                // No need to keep that power domain explicitly, unlike EXT1.
                ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_0));
                ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_0));


                //充电按键
                gpio_reset_pin(2);
                const int ext_wakeup_pin_1 = 2;
                const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
                printf("Enabling EXT1 wakeup on pins GPIO%d\r\n",ext_wakeup_pin_1);
                ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW));




                esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
                ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup());


                #endif
                esp_deep_sleep_start();
            }else 
            {


                 int btn = left_adc_wake_btn_send();
                 ESP_LOGE(LOG_TAG,"btn = %d",btn);
                    Machine_info.left_state = btn;

                    // Set duty to 50%
                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
                    vTaskDelay(30 / portTICK_PERIOD_MS);
                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));


                
                    #if 1
                        if(xQueueSend(left_screen_queue,&Machine_info,portMAX_DELAY) != true)
                        {
                            printf("left send fail\r\n");
                        } 
                    #endif 

                        while(1)
                        {
                            vTaskDelay(20 / portTICK_PERIOD_MS);
                        }


            }



    }
#endif






    }




#if 0
//  info_init();
//  board_init();

#else





#if USER_DEEP_SLEEP_ENABLE
   int reson  = is_wake_up_reson();  //返回唤醒的原因
   printf(" info_init reson = %d\r\n",reson);
    //idf.py 设置分区
    spiffs_init();

    /* not a wakeup from ULP, load the firmware */
    if ((reson != ESP_SLEEP_WAKEUP_ULP) && (reson != ESP_SLEEP_WAKEUP_TIMER)) 
    {
       
        #if 1
            //uint8_t yc_name[6] = {0xd2,0xcf,0xb3,0xb2,0x00,0x00};
            Machine_info_t default_info={
                .left_display_mode = 0,
                //.left_state =1,
                .eflagID = 0xFF,
                .rssi = 0x64,
                .refresh_cycle = 2,
				.batt_precent = 100,
            };
            spiffs_write(&default_info);
        #endif
            spiffs_read(&Machine_info);


    }else
    {


    }
#endif







#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE ||  USER_DEEP_SLEEP_ENABLE
    lora_init();    
#endif


#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
    adc1_init();
#endif


#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE

    button_init(adc1_handle);        //左侧按键
    power_button_init(adc1_handle);  //右侧电源按键

    Machine_info.batt_precent =  read_battery_voltage();

    Machine_info.last_batt_precent = Machine_info.batt_precent;

#endif


#if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
//timer_init();
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////
 #endif

xTaskCreate( button_task,"button_task",5*2048, NULL, configMAX_PRIORITIES, NULL);

xTaskCreate( right_screen_task, "right_screen_task",15*1024, NULL, configMAX_PRIORITIES - 2, NULL);


printf("=================================UPDATE OK===========================\r\n");


#if 1
 xTaskCreate( business_logic_task, "business_logic_task", 25*1024, NULL, YC_TASK_NONE, NULL);
 //xTaskCreate( unpack_task, "unpack_task", 5*1024, NULL, YC_TASK_UNPACK, NULL);
 #if !USER_QIXIN  //
 xTaskCreate( lora_task, "lora_task", 5*1024, NULL, configMAX_PRIORITIES, NULL);

 #endif

 #if 0
 xTaskCreate(gui_task, "gui_task", 4096 * 2, NULL, 5, NULL);
 #endif

#if 1  //任务处理函数
 xTaskCreate(read_deal_data_callback_handler, "read_deal_data_task", 1024*8, NULL, configMAX_PRIORITIES , NULL);
#endif

    //添加定时发送当前是否有链表数据
    // xTaskCreate(Sendlist_task_callback_handler, "Sendlist_task", 1024*8, NULL, configMAX_PRIORITIES, NULL);
#endif


//打印系统信息
print_systenInfo();


}

// static void board_init(void)
// {

// #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
// led_init();
// #endif


// #if USER_DEEP_SLEEP_ENABLE
// int reson  = is_wake_up_reson();  //返回唤醒的原因
//  /* ULP Risc-V read and detected a temperature above the limit */
// if (reson == ESP_SLEEP_WAKEUP_ULP)
// {



//                        // Set duty to 50%
//                     ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
//                     // Update duty to apply the new value
//                     ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

//                     vTaskDelay(30 / portTICK_PERIOD_MS);

//                     ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
//                     // Update duty to apply the new value
//                     ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
// }
//  #endif

// #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
//    font_init();
// #endif

//  #if HARDWARE_SPI


// #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
// epd_init();
// #endif

// #else
//     left_screen.epd_name = "left_screen";
//     left_screen.busy_pin = 42;
//     left_screen.res_pin = 41;
//     left_screen.dc_pin = 40;
//     left_screen.cs_pin = 39;
//     left_screen.sclk_pin = 48;
//     left_screen.sda_pin = 45;
//     epd_screen_init(&left_screen);

//     right_screen.epd_name = "right_screen";
//     right_screen.busy_pin = 13;
//     right_screen.res_pin = 14;
//     right_screen.dc_pin = 21;
//     right_screen.cs_pin = 47;
//     right_screen.sclk_pin = 48;
//     right_screen.sda_pin = 45;

//     epd_screen_init(&right_screen);
// #endif












//     #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
//     timer_init();
//     #endif


//     #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
//     //adc1_init();
//     #endif

//     //adc_read_power_pin();
//     //ESP_LOGI(LOG_TAG,"board_init");





//     #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE || USER_DEEP_SLEEP_ENABLE
//     button_init(adc1_handle);
//     #endif


 


// #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE ||  USER_DEEP_SLEEP_ENABLE
//     lora_init();
// #endif
    
// }



static void left_screen_task(void* arg)
{

    extern bool is_sleep;

  

     #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE

        int  reson = is_wake_up_reson();  //返回唤醒的原因
        if ((reson != ESP_SLEEP_WAKEUP_ULP) && (reson != ESP_SLEEP_WAKEUP_TIMER)&&(reson != ESP_SLEEP_WAKEUP_EXT0)) 
        {
            Paint_leftScreen_main_powerOn();
        }

     #endif



    Machine_info_t info;   


    // if(reson == ESP_SLEEP_WAKEUP_EXT0)
    // {
    //     //开机刷新左屏慕
    //      Paint_leftScreen_main_slow(&info);
    // }




    while(1)
    {
        if(xQueueReceive(left_screen_queue, &info,(TickType_t)portMAX_DELAY))
        {

            font_exit_sleep();

            printf("left 拿锁\n");
            //if(xSemaphoreTake(screen_semaphore, portMAX_DELAY) == true)
            if(1)
            {
                if(Machine_info.left_current_Quick_refresh_time >=  Machine_info.left_max_Quick_refresh_time)
                {
                    Machine_info.left_current_Quick_refresh_time = 0;
                    Paint_leftScreen_main_slow(&info);
                }
                else
                {
                    // printf("left_current_Quick_refresh_time = %d,Machine_info.left_max_Quick_refresh_time= %d\r\n",Machine_info.left_current_Quick_refresh_time,Machine_info.left_max_Quick_refresh_time);
                    Machine_info.left_current_Quick_refresh_time++;
                    Paint_leftScreen_main_quick(&info);
                }
                printf("left 还锁\n");
                //xSemaphoreGive(screen_semaphore);
            }
            else
            {
                ESP_LOGE(LOG_TAG,"left 拿锁失败 \n");
            }



            while(1)
        {                         
            if( (left_refresh_timer_isActive() == false) )
            {
                printf("7left refresh complete %s\r\n",left_refresh_timer_isActive()?"true":"false");
                break;
            }
                vTaskDelay(100/ portTICK_PERIOD_MS);
        }





            if(
                (Machine_info.power_status == 1)&&

                (Machine_info.paired == 1)  //已配对

            )
            {

                sleep_timer_start(100);  //进入睡眠

            }

if(Machine_info.power_status == 0)
{


    
                                printf("=>deep sleep\r\n");
                                uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
                                 //vTaskDelay(100/ portTICK_PERIOD_MS);

#if 1           //电源按键
                           // adc_oneshot_del_unit(adc1_handle);
                            gpio_reset_pin(4);
                            int ext_wakeup_pin_0 = 4;
                            printf("Enabling EXT0 wakeup on pin GPIO%d\n", ext_wakeup_pin_0);
                            ESP_ERROR_CHECK(esp_sleep_enable_ext0_wakeup(ext_wakeup_pin_0, 0));

                            // Configure pullup/downs via RTCIO to tie wakeup pins to inactive level during deepsleep.
                            // EXT0 resides in the same power domain (RTC_PERIPH) as the RTC IO pullup/downs.
                            // No need to keep that power domain explicitly, unlike EXT1.
                            ESP_ERROR_CHECK(rtc_gpio_pullup_en(ext_wakeup_pin_0));
                            ESP_ERROR_CHECK(rtc_gpio_pulldown_dis(ext_wakeup_pin_0));


                            esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
                            ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup());

#endif
                                //adc_oneshot_del_unit(adc1_handle);
                                esp_deep_sleep_start();


}



                        // if(Machine_info.paired == 1)  //已配对
                        // {
                        //             if(is_sleep == false)  //已经进入sleep定时器
                        //             {
                        //                 printf("已配对 进入睡眠\n");
                        //                 sleep_timer_start(100);  //进入睡眠
                        //             }
                        // }


       

            #if  0
                            int reson  = is_wake_up_reson();  //返回唤醒的原因
                            /* ULP Risc-V read and detected a temperature above the limit */
                            if (reson == ESP_SLEEP_WAKEUP_ULP || reson == ESP_SLEEP_WAKEUP_TIMER) {
                                 //lora_set_power_level(0);


                                #if 0
                                font_into_sleep();   //关闭外设电源
                                epd_sleep(SCREEN_LEFT);
                                epd_sleep(SCREEN_RIGHT);
                                #endif


                                #if USER_LIGHT_SLEEP_ENABLE

                               

                                if(is_sleep == true)  //已经进入sleep定时器
                                {
                                    printf("display refresh commplete ready sleep\r\n");


                                        if(Machine_info.paired == 1)  //已配对
                                       {
                                            //if(is_sleep == false)  //已经进入sleep定时器
                                            {
                                                       sleep_timer_start(100);  //进入睡眠
                                            }
                                       }
                                }else
                                {
                                    printf("display refresh commplete not into sleep\r\n");

                                }
                                //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US);  //配置当前休眠的唤醒时间
                                //esp_light_sleep_start();
                                #endif

                                #if USER_DEEP_SLEEP_ENABLE
                                //esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
                                //重新配置休眠唤醒时间
                                //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US);  //配置当前休眠的唤醒时间
                                //esp_deep_sleep_start();
                                #endif
                            }else 
                            {
                                if(Machine_info.paired == 1)  //已配对
                                {
                                    if(is_sleep == false)  //已经进入sleep定时器
                                    {
                                        printf("已配对 进入睡眠\n");
                                        sleep_timer_start(100);  //进入睡眠
                                    }
                                }
                            }
            #endif                    
        }
        
    }
}

static void right_screen_task(void* arg)
{

    extern bool is_sleep;

      #if USER_DEEP_SLEEP_ENABLE

        int  reson = is_wake_up_reson();  //返回唤醒的原因
        if ((reson != ESP_SLEEP_WAKEUP_ULP) && (reson != ESP_SLEEP_WAKEUP_TIMER)) 
        {
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            Paint_rightScreen_main_powerON();
        } 
     #endif


    // #if USER_NOT_SLEEP_ENABLE || USER_LIGHT_SLEEP_ENABLE

    //     //vTaskDelay(1000 / portTICK_PERIOD_MS);
    //     Paint_rightScreen_main_powerON();

    //  #endif




             int  reson = is_wake_up_reson();  //返回唤醒的原因
        //if ((reson != ESP_SLEEP_WAKEUP_ULP) && (reson != ESP_SLEEP_WAKEUP_TIMER)&&(reson != ESP_SLEEP_WAKEUP_EXT0)) 
        {
            Paint_rightScreen_main_powerON();
        }

         vTaskDelay(3000 / portTICK_PERIOD_MS);


    Machine_info.rssi = 100;//没有获取到真数据，默认100

    Machine_info_t info;
    while(1)
    {
        if(xQueueReceive(right_screen_queue, &info, (TickType_t)portMAX_DELAY))
        {
            font_exit_sleep();
            ESP_LOGD(LOG_TAG,"right_screen_task");


            printf("refresh %d,max %d\r\n",Machine_info.right_current_Quick_refresh_time,Machine_info.right_max_Quick_refresh_time);


            printf("right 拿锁\n");
            //if(xSemaphoreTake(screen_semaphore, portMAX_DELAY) == true)
            if(1)
            {
                if(Machine_info.right_current_Quick_refresh_time >=  Machine_info.right_max_Quick_refresh_time)
                {
                    Machine_info.right_current_Quick_refresh_time = 0;
                    Paint_rightScreen_main_slow(&info);
                }else
                {
                    Machine_info.right_current_Quick_refresh_time++;
                    // Paint_rightScreen_main_quick(&info);
                    Paint_rightScreen_main_slow(&info);
                }
                printf("right 还锁\n");
                //xSemaphoreGive(screen_semaphore);
            }
            else
            {
                ESP_LOGE(LOG_TAG,"right 拿锁失败 \n");
            }



         while(1)
        {                         
            if( (right_refresh_timer_isActive() == false) )
            {
                printf("8left refresh complete %s\r\n",right_refresh_timer_isActive()?"true":"false");
                break;
            }
                vTaskDelay(100/ portTICK_PERIOD_MS);
        }



            #if  1
                            int reson  = is_wake_up_reson();  //返回唤醒的原因
                            /* ULP Risc-V read and detected a temperature above the limit */
                            if (reson == ESP_SLEEP_WAKEUP_ULP || reson == ESP_SLEEP_WAKEUP_TIMER) {
                                 //lora_set_power_level(0);



                                 
                                #if USER_LIGHT_SLEEP_ENABLE

                               

                                if(is_sleep == true)  //已经进入sleep定时器
                                {
                                    printf("display right refresh commplete ready sleep\r\n");

                                         if(Machine_info.paired == 1)  //已配对
                                       {
                                            //if(is_sleep == false)  //已经进入sleep定时器
                                            {
                                                       sleep_timer_start(100);  //进入睡眠
                                            }
                                       }
                                }else
                                {
                                    printf("display right refresh commplete not into sleep\r\n");

                                }
                                //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US);  //配置当前休眠的唤醒时间
                                //esp_light_sleep_start();
                                #endif



                                #if 0
                                font_into_sleep();   //关闭外设电源
                                epd_sleep(SCREEN_LEFT);
                                epd_sleep(SCREEN_RIGHT);
                                #endif

                                #if USER_LIGHT_SLEEP_ENABLE
                                //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US);  //配置当前休眠的唤醒时间
                                //esp_light_sleep_start();
                                #endif

                                #if USER_DEEP_SLEEP_ENABLE
                                //重新配置休眠唤醒时间
                                //esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US);  //配置当前休眠的唤醒时间
                                //esp_deep_sleep_start();
                                #endif
                            }else 
                            {
                                       if(Machine_info.paired == 1)  //已配对
                                       {
                                            if(is_sleep == false)  //已经进入sleep定时器
                                            {
                                                sleep_timer_start(100);  //进入睡眠
                                            }
                                       }


                                printf("sleep = %d\r\n",is_sleep);
                            }
            #endif           



        }
    }
}
static void button_task(void* arg)
{
    //update_last_button_info(Machine_info.current_button.button_info);//初始化上个按键为运行，用作paint0703计时
    uint8_t button_info;
    while(1)
    {
        if(xQueueReceive(button_Data_queue, &button_info, (TickType_t)portMAX_DELAY))
        {
            
            ESP_LOGI(LOG_TAG,"btn_flag[%d][%d][%d][%d][%d][%d],button_info = [%d]%s ",Machine_info.btn_dis_flag[0],\
            Machine_info.btn_dis_flag[1],Machine_info.btn_dis_flag[2],Machine_info.btn_dis_flag[3],Machine_info.btn_dis_flag[4],\
            Machine_info.btn_dis_flag[5],button_info,Machine_info.power_status?"开机":"关机");

            ESP_LOGI(LOG_TAG,"batt_precent[%d]\ncid[%s]\nlast_button[%d]\nlora_new_channel[%d]\neflagID[%d]\nDuration_time[%ld]rssi[%d]paired[%s]",\
                                Machine_info.batt_precent,\
                                Machine_info.cid,\
                                Machine_info.last_button.button_info,\
                                Machine_info.lora_new_channel,\
                                Machine_info.eflagID,\
                                Machine_info.Duration_time,\
                                Machine_info.rssi,\
                                Machine_info.paired?"已配网":"未配网");

            if(button_info < 0x12)  //左屏慕按键
            {
                if(Machine_info.btn_dis_flag[button_info-1] == false)
                {
                    printf("按键关闭，默认运行\n");
                    button_info = STATE_OPERATION;//按键关闭，默认运行
                    if((Machine_info.power_status == 1) &&  (Machine_info.paired == 1))
                    {
                        sleep_timer_start(100);  //进入睡眠
                    }

                }
                Machine_info .current_button.button_info =  button_info;
            //判断当前的按键状态 设置为当前状态后 再次按键不处理
            printf("last btn = %d ,curr btn = %d\n",Machine_info.last_button.button_info , Machine_info.current_button.button_info);
            if(Machine_info.last_button.button_info !=  Machine_info.current_button.button_info)
            {        
                    if(Machine_info.paired == 1)
                    {
                        printf("paired add data to list chanl = 0x%02x\r\n",Machine_info.lora_new_channel);
                        getRtcTime(&Machine_info);  //获取当前时间
                        //更新当前时间
                        Machine_info.current_button.button_info = button_info;
                        Machine_info.current_button.Year = Machine_info.year;
                        Machine_info.current_button.Month = Machine_info.month;
                        Machine_info.current_button.Day = Machine_info.day;
                        Machine_info.current_button.Hour = Machine_info.hour;
                        Machine_info.current_button.Minute = Machine_info.min;
                        Machine_info.current_button.Second = Machine_info.sec;

                        long long  current_Duration_time  =   calculate_minutes_difference
                        (
                            Machine_info.last_button.Year,
                            Machine_info.last_button.Month ,
                            Machine_info.last_button.Day ,
                            Machine_info.last_button.Hour ,
                            Machine_info.last_button.Minute ,
                            Machine_info.last_button.Second ,

                            Machine_info.current_button.Year,
                            Machine_info.current_button.Month ,
                            Machine_info.current_button.Day ,
                            Machine_info.current_button.Hour ,
                            Machine_info.current_button.Minute ,
                            Machine_info.current_button.Second
                        );


                        Machine_info.Duration_time = current_Duration_time;//持续时长

                        printf("Machine_info.Duration_time = %ld\r\n",Machine_info.Duration_time);
                        
                        terminal_send_data();  //添加数据队列
                       
                       #if 0
                                printf("list before\r\n");
                                printList(Send_list);

                                    if(Machine_info.Duration_time == 0)
                                    {
                                        deleteNode_head(Send_list);
                                    }

                                printf("list after\r\n");
                                printList(Send_list);
                       #endif


                        
                        

                        set_status_heights();
                         Machine_info.Duration_time = 0;

                        //更新上次的状态
                        update_last_button_info(Machine_info.last_button.button_info);
                    }else
                    {
                        //  f_send_get_chart_data();
                        printf("not add data to list\r\n");
                    }

                    Machine_info.last_button.button_info =  Machine_info.current_button.button_info;
                    // Machine_info.left_state = button_info;
                    Machine_info.left_state = Machine_info.current_button.button_info;
                    ESP_LOGE(LOG_TAG,"----Machine_info.left_state = %d",Machine_info.left_state);
#if 1
                    if(xQueueSend(left_screen_queue,&Machine_info,portMAX_DELAY) != true)
                    {
                        ESP_LOGE(LOG_TAG,"queue:left_screen_queue");
                    } 
#endif 
                    // Set duty to 50%
                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
                    vTaskDelay(30 / portTICK_PERIOD_MS);
                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));


                    //printList(Send_list);
                    //printList(list_head);
            }
            else//和上个按键重复，唤醒原因为ulp唤醒，不进入休眠
            {
                printf("和上个按键重复，唤醒原因为ulp唤醒，不进入休眠\r\n");
                sleep_timer_start(100); //开始进入倒计时休眠 
            }
            }else //右屏幕按键触发
            {

                if(button_info == POWER_ON_PRESS_VALUE)   //power 开机时短按
                {
                    // Set duty to 50%
                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                    vTaskDelay(30 / portTICK_PERIOD_MS);

                    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                    // Update duty to apply the new value
                    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));


                    if( (Machine_info.power_status == 1) &&  (Machine_info.paired == 1))
                    {
                        //判断当前开机 是否配对 继续执行时间片操作
                        sleep_timer_start(100); //开始进入倒计时休眠 
                    }
                }

                if(button_info == POWER_OFF_PRESS_VALUE) //power  关机时短按
                {
                  sleep_timer_start(100); //开始进入倒计时休眠    
                }


                
                if(button_info == POWER_ON_INTO_STATUS_CHANGE_VALUE) //power 长按触发
                {
                        // Set duty to 50%
                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
                        // Update duty to apply the new value
                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                        vTaskDelay(1000 / portTICK_PERIOD_MS);


                        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
                        // Update duty to apply the new value
                        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

                        if(Machine_info.power_status == 1)  //开机状态
                        {
                            Machine_info.power_status = 0;
                            dis_instructions();
                            vTaskDelay(1000 / portTICK_PERIOD_MS);
                            sleep_timer_start(100); //开始进入倒计时休眠 
    
                            printf("last power on current power off ready sleep\r\n");
                            // sleep_timer_start(100); //开始进入倒计时休眠 //更改为刷完两个屏幕，倒计时
                        }
                        else if(Machine_info.power_status == 0)  
                        {
                            printf("power on\r\n");
                            Machine_info.power_status = 1;
                            lora_set_power_level(1);
                            font_exit_sleep();


                            gpio_hold_dis(LORA_TXD_PIN);
                            gpio_hold_dis(LORA_RXD_PIN);


                            gpio_hold_dis(PIN_L_CS);
                            gpio_hold_dis(PIN_R_CS);

                            //恢复串口i功能
                            uart_sleep_out_config();
                            

                            Paint_leftScreen_main_slow(&Machine_info);
                            Paint_rightScreen_main_slow(&Machine_info);
                            // Paint_leftScreen_main_quick(&Machine_info);
                            // Paint_rightScreen_main_quick(&Machine_info);

                            if( (Machine_info.power_status == 1) &&  (Machine_info.paired == 1))
                            {
                                //判断当前开机 是否配对 继续执行时间片操作
                                sleep_timer_start(100); //开始进入倒计时休眠 
                            }
                        }

                }


                if(button_info == POWER_ON_INTO_DIS_RIGHT) 
                {
                    if(xQueueSend(right_screen_queue,&Machine_info,portMAX_DELAY) != true)
                    {
                        ESP_LOGE(LOG_TAG,"queue:right_screen_queue");
                    } 
                }



                if(button_info == POWER_ON_INTO_OTA_VALUE) //进入OTA模式
                {
                    beep_blink(50,3);
                    printf("into ota mode\r\n");
                    esp_ble_ota();
                }



                if(button_info == POWER_ON_INTO_RESET_VALUE) //进入配网模式
                {
                    beep_blink(2000,1);
                    printf("into reset mode\r\n");

                    font_exit_sleep();
                    lora_set_power_level(1);
                    uart_sleep_out_config();
                   

                    
                    #include "user_sleep.h"
                    //#include "esp_sleep.h"

                    extern void sleep_timer_stop();
                    extern void Already_send_timer_stop();

                    sleep_timer_stop();
                    Already_send_timer_stop();

                    // //修改信道前修改设备ID 及 设备ID
                    // dymatic_change_device_id(0x00000001);
                    // dymatic_change_dst_device_id(0xFFFFFFFF);
                    // //切换信道
                    // dymatic_change_chanel(Machine_info.lora_factory_channel);  //切换信道
                    // // spiffs_read(&Machine_info);


                    // vTaskDelay(300 / portTICK_PERIOD_MS);
                    reset_default(true);
                    reset_lora();
                    vTaskDelay(300 / portTICK_PERIOD_MS);
                }
            }
            
        }

    }
}

static void business_logic_task(void* arg)
{
    //YC_DATA_T tmp;
    int len = 0;
    bool is_refresh =false;
    for(;;)
    {   
        if(xQueueReceive(yc_data_queue, &len, (TickType_t)portMAX_DELAY)) 
        {
#if 1
            is_refresh = subcontract(&yc_data);
            if(is_refresh)
            {
                screen_display();
            }else
            {
                printf("not display fresh\r\n");
            }
#endif
            free(yc_data.data);  //释放内存 
            yc_data.data = NULL;
            yc_data.len = 0;
            yc_data.index = 0;
        }
    }    
}

static void unpack_task(void* arg)
{
    LORA_DATA_T tmp_data;
    extern esp_timer_handle_t lora_timer;
    for(;;)
    {   
        if(xQueueReceive(lora_data_queue, &tmp_data, (TickType_t)portMAX_DELAY)) 
        {
            if(!esp_timer_is_active(lora_timer))
            {
                lora_timer_start();
            }
            else
            {
                lora_timer_restart();
            }

            yc_data.len += tmp_data.data_len;
            memcpy(yc_data.data+yc_data.index,tmp_data.data_buf,tmp_data.data_len);
            yc_data.index += tmp_data.data_len;
        }
    }
}

static void lora_task(void* arg)
{
    lora_event_task(arg);
}




// /*********************************************************************************
// * function   :   Sendlist_task_callback_handler     
// * Description :  发送处理链表函数
// * Input       :  
// * Output      :  
// * Author      :  祁鑫                  Data : 2023 9.12
// **********************************************************************************/
// void Sendlist_task_callback_handler()
// {
//   int length = 0;


//  	 uint8_t* result = (uint8_t*) malloc(buffer_size+1);

//  	TickType_t xLastWakeTime;
//     #if 0
//     const TickType_t xFrequency = 400/10; // 定时通知的间隔
//     #else
//     const TickType_t xFrequency = 500/10; // 定时通知的间隔
//     #endif

//     // 初始化xLastWakeTime
//     xLastWakeTime = xTaskGetTickCount();


// 	int receive_times = 0;
// 	int user_size = 0;
// 	int result_length = 0;
// 	//int result_length = 0;
// 	static int result_index = 0;
// 	int result_data_len = 0;


//   while (1) {

// #if 0
// 	    //定时通知数据处理任务有新数据可用
//         vTaskDelayUntil(&xLastWakeTime, xFrequency);
// #endif   
//         if(xQueueReceive(Send_Data_queue, &length, portMAX_DELAY) == pdPASS)
//         {
//             //int len = countNodes(Send_list); /* returns the number of nodes in the list */
//             Node *list = Send_list;  //发送数据链表    
//             int len = countNodes(Send_list); /* returns the number of nodes in the list */

//             if(len!=0)
//             {
//                 printf("current wait send num data=%d\r\n",len);
//                 #if 1
            
//                 //int len = countNodes(list); /* returns the number of nodes in the list */
//                 while(len)
//                 {
//                     //int busy = get_lora_busy_pin();
//                     //printf("busy = %d\r\n",busy);   

//                     printf("send times\r\n");
//                     //if()
//                     lora_send_data((char *)list->data,list->len);
//                     list=list->next;
//                     len--;
//                 }
//                 //Send_list = deleteList(Send_list); 
//                 free(list);
//                 #endif
//             }
//             #if 0
//                         for (int i = 0; i < len; i++)
//                         {
//                             printf("%02x",result[i]);
//                         }
//             #endif

//     }	     
        
//   }


// }




/*********************************************************************************
* function   :   uart_task_callback_handler     
* Description :  串口0函数
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 9.12
**********************************************************************************/
void uart_task_callback_handler()
{
// #include "driver/uart.h"
 
//     uint8_t dtmp[200]= {0};

//     while (1) 
//     {


     
//         printf("uart 0 rev = ");  


//        int len = uart_read_bytes(UART_NUM_0, dtmp, 1024,200/portTICK_PERIOD_MS);
//         if(len)
//         {

//         for(int i = 0;i<len;i++)
//         printf("%02X",dtmp[i]);
//         printf("\r\n");

//         }

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

//         vTaskDelay(1000 / portTICK_PERIOD_MS);
//     }





        
}

/*********************************************************************************
* function   :   read_deal_data_callback_handler     
* Description :  定时处理函数
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 9.12
**********************************************************************************/
void read_deal_data_callback_handler()
{

    #if 0
  int length = 0;


 	 uint8_t* result = (uint8_t*) malloc(buffer_size+1);

 	TickType_t xLastWakeTime;
    #if 1
    const TickType_t xFrequency = 100/10; // 定时通知的间隔
    #else
    const TickType_t xFrequency = 500; // 定时通知的间隔
    #endif

    // 初始化xLastWakeTime
    xLastWakeTime = xTaskGetTickCount();


	int receive_times = 0;
	int user_size = 0;
	int result_length = 0;
	//int result_length = 0;
	static int result_index = 0;
	int result_data_len = 0;

    #include "y_ringbuf.h"
    extern struct RINGBUF_st;
    extern RINGBUF_st *lora_ringbuf;


  while (1) {

	 // 定时通知数据处理任务有新数据可用
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
		user_size = y_ringbuf_get_used_size(lora_ringbuf);
        #if USER_OTA
        if(user_size>=0)
        #endif
         if(user_size>0)
        {           
#if 0
            for (int i = 0; i < len; i++)
            {
                printf("%02x",result[i]);
            }
#endif

		     printf("times comming length=%d\r\n",user_size);

             if(user_size == 36)
             {
                y_ringbuf_read_clear(lora_ringbuf, result, user_size); //读取并清除数据
             }

             #if 1
             int len = y_ringbuf_read_clear(lora_ringbuf, result, user_size); //读取并清除数据
             yc_data.len =  user_size;
             yc_data.data = malloc(sizeof(uint8_t)*user_size);//分配内存
             memcpy(yc_data.data,result,user_size);
            //lora_send_queue_callback(result,len);  //发送消息处理函数

            if(xQueueSend(yc_data_queue,&len,0) != true)
            {
                ESP_LOGE(LOG_TAG,"yc_data_queue send is fail");
            }
            #endif


#if USER_OTA
            if((user_size>1024)||(user_size == 0) || (((user_size<1024))&&(is_ota ==true)) )
            if(xQueueSend(ota_queue,&user_size,0) != true)
            {
                    ESP_LOGE(LOG_TAG,"ota_queue send is fail");
            }
#endif
         

        }

  }
  #else

    int length = 0;
    uint8_t* result = (uint8_t*) malloc(buffer_size+1);
	int user_size = 0;

    while(1){
        if(xQueueReceive(lora_dealhandle, &length, portMAX_DELAY) == pdPASS)
        {
            if(rssi!=0)
            {
                Machine_info.rssi = rssi;
            }

            //printf("deal data\r\n");
            user_size = y_ringbuf_get_used_size(lora_ringbuf);
            if(user_size>0)
            {  
                printf("times comming length=%d\r\n",user_size);
            #if 0
            if(user_size == 36)
            {
                y_ringbuf_read_clear(lora_ringbuf, result, user_size); //读取并清除数据

                #if 1
                for (int i = 0; i < user_size; i++)
                {
                    printf("%02x",result[i]);
                }
                #endif
            }else
            #endif
                {
#if 1
                    int len = y_ringbuf_read_clear(lora_ringbuf, result, user_size); //读取并清除数据
    #if 1
                    for (int i = 0; i < user_size; i++)
                    {
                        printf("%02x",result[i]);
                    }
                    printf("\r\n");
    #endif
                    yc_data.len =  user_size;
                    yc_data.data = malloc(sizeof(uint8_t)*user_size);//分配内存
                    memcpy(yc_data.data,result,user_size);
                    //lora_send_queue_callback(result,len);  //发送消息处理函数
                    if(xQueueSend(yc_data_queue,&len,(TickType_t)portMAX_DELAY) != true)
                    {
                        ESP_LOGE(LOG_TAG,"yc_data_queue send is fail");
                    }
#endif
                }
            }
        }
    }







  #endif
}



// #define MY_DISP_HOR_RES    648
// #define MY_DISP_VER_RES    480
// #define DISP_BUF_SIZE (480 * 648)


// volatile bool disp_flush_enabled = true;

// /* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL
//  */
// void disp_enable_update(void)
// {
//     disp_flush_enabled = true;
// }

// /* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL
//  */
// void disp_disable_update(void)
// {
//     disp_flush_enabled = false;
// }

// /*Flush the content of the internal buffer the specific area on the display.
//  *`px_map` contains the rendered image as raw pixel map and it should be copied to `area` on the display.
//  *You can use DMA or any hardware acceleration to do this operation in the background but
//  *'lv_display_flush_ready()' has to be called when it's finished.*/


// void disp_driver_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map)
// // static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, lv_color_t * px_map)
// {
//     //printf("-------------------disp_flush \r\n");
//     if(disp_flush_enabled) {
//         /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
//         int32_t x;
//         int32_t y;
//         printf("%d,%d,%d,%d\r\n",area->x1, area->y1, area->x2, area->y2);
//         epd_partial_cache1(  area->x1, area->y1, area->x2, area->y2,SCREEN_LEFT,color_map);
//         epd_powerOn_refresh(SCREEN_LEFT);
//     #if 0
//         for(y = area->y1; y <= area->y2; y++) {
//             for(x = area->x1; x <= area->x2; x++) {
//                 printf("%ld,%ld\r\n",x,y);
//                 /*Put a pixel to the display. For example:*/
//                 /*put_px(x, y, *px_map)*/
//                 px_map++;
//             }
//         }
//      #endif   
//     }


//     /*IMPORTANT!!!
//      *Inform the graphics library that you are ready with the flushing*/
//     #if 0
//     lv_display_flush_ready(disp_drv);
//     #else
 
//     lv_disp_flush_ready(drv);
//     #endif
// }

// #if 0
// static uint8_t *buf_3_1;
// static uint8_t *buf_3_2;
// #else
// static uint8_t *buf;
// #endif


// static void gui_task(void* pvParameter)
// {



//     #if 0
//     lv_init();

//     //buf= heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA|MALLOC_CAP_SPIRAM);
//     //assert(buf != NULL);



//     /*------------------------------------
//      * Create a display and set a flush_cb
//      * -----------------------------------*/
//     lv_display_t * disp = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);
//     lv_display_set_flush_cb(disp, disp_flush);



//     /* Example 3
//      * Two buffers screen sized buffer for double buffering.
//      * Both LV_DISPLAY_RENDER_MODE_DIRECT and LV_DISPLAY_RENDER_MODE_FULL works, see their comments*/
 
//     buf_3_1= heap_caps_malloc(MY_DISP_HOR_RES *MY_DISP_VER_RES, MALLOC_CAP_8BIT);
//     buf_3_2= heap_caps_malloc(MY_DISP_HOR_RES *MY_DISP_VER_RES, MALLOC_CAP_8BIT);

//     if(buf_3_1 ==NULL)
//     {
//     printf("-------------------buf_3_1 \r\n");

//     }

//     if(buf_3_2 ==NULL)
//     {
//     printf("-------------------buf_3_2 \r\n");

//     }



//     lv_display_set_draw_buffers(disp, buf_3_1, buf_3_2, sizeof(buf_3_1)*MY_DISP_HOR_RES *MY_DISP_VER_RES, LV_DISPLAY_RENDER_MODE_DIRECT);




// lv_theme_t * th = lv_theme_mono_init(disp, true, &lv_font_montserrat_14);

// bool is = lv_theme_mono_is_inited();

// if(is)printf("========================ok=================\r\n");
// else printf("========================fail=================\r\n");


//    lv_disp_set_theme(disp, th); /*Assign the theme to the display*/

//     /*Create a white label, set its text and align it to the center*/
//     lv_obj_t * label = lv_label_create(lv_scr_act());
//     lv_label_set_text(label, "Hello world");
//     lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
//     lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);




// #else

//    lv_init();
//     //disp_driver_init();
//     static lv_disp_draw_buf_t disp_buf;

//     uint32_t size_in_px = DISP_BUF_SIZE;

//     buf= heap_caps_malloc(MY_DISP_HOR_RES *MY_DISP_VER_RES, MALLOC_CAP_8BIT);


//     lv_disp_draw_buf_init(&disp_buf, buf, NULL, size_in_px);

//     lv_disp_drv_t disp_drv;
//     lv_disp_drv_init(&disp_drv);

//     disp_drv.flush_cb = disp_driver_flush;
//     disp_drv.hor_res = 648;
//     disp_drv.ver_res = 480;
//     disp_drv.full_refresh = 1;
//     disp_drv.draw_buf = &disp_buf;

//     lv_disp_t * disp = lv_disp_drv_register(&disp_drv);


// lv_disp_rot_t dir = lv_disp_get_rotation(disp);
// lv_disp_set_rotation(disp, LV_DISP_ROT_180);

// printf("dir=%d\r\n",dir);



//    /*Create a white label, set its text and align it to the center*/
//     lv_obj_t * label = lv_label_create(lv_scr_act());
//     lv_label_set_text(label, "Hello world");

//     lv_obj_set_style_bg_color(lv_scr_act(), lv_color_make(0,0,0), 0);//设置背景颜色为白色

//     lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
//     lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);




//     lv_obj_t * label1 = lv_label_create(lv_scr_act());
//     lv_label_set_text(label1, "world");
//     //lv_obj_set_style_bg_color(lv_scr_act(), lv_color_make(0,0,0), 0);//设置背景颜色为白色
//     lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
//     //lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
//     lv_obj_set_pos(label1,0,20);



//     //sgf_lvgl_display(&info);
//     lv_refr_now(NULL);
//     // if (wait_second != 0) {
//     //     ESP_LOGI(TAG, "wait=%ds", wait_second);
//     //     vTaskDelay(pdMS_TO_TICKS(1000 * wait_second));
//     // }
//     // gpio_weekup_init_s(sleep_second);


// #endif






//     //lv_refr_now(disp);
//     for(;;) {

//       lv_tick_inc(10); /*Use a not round number to cover more anim states */
//       lv_timer_handler();
//       vTaskDelay(10 / portTICK_PERIOD_MS);
//       }



   


// }














