#include <stdio.h>
#include "EPD.h"
#include <string.h>

#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "GUI_Paint.h"
#include "freertos/timers.h"
//#include "../components/../main/user_sleep.h"
#include "esp_timer.h"


TimerHandle_t left_display_timer;

TimerHandle_t right_display_timer;


bool left_refresh_complete = false;
bool right_refresh_complete = false;


uint8_t current_display = 0;

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









void left_slow_timerout_Callback(TimerHandle_t xTimer) {
    // 在这里执行定时器超时后的任务
    // 注意：回调函数中不要执行耗时的操作，避免影响其他任务的运行


    //if(current_display == SCREEN_LEFT)
    {
         left_refresh_complete = true;   
    }

    //     if(current_display == SCREEN_RIGHT)
    // {
    //     right_refresh_complete = true;
    // }

}




void right_slow_timerout_Callback(TimerHandle_t xTimer) {
    // 在这里执行定时器超时后的任务
    // 注意：回调函数中不要执行耗时的操作，避免影响其他任务的运行


    // if(current_display == SCREEN_LEFT)
    // {
    //      left_refresh_complete = true;   
    // }

       // if(current_display == SCREEN_RIGHT)
    {
        right_refresh_complete = true;
    }

}






/*********************************************************************************
* function   :   refresh_timer_start     
* Description :  
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void left_refresh_timer_start(int ms)
{

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

/*********************************************************************************
* function   :   refresh_timer_stop     
* Description :  
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void left_refresh_timer_stop(void)
{
    xTimerStop(left_display_timer, 0);   //停止定时器
}





/*********************************************************************************
* function   :   refresh_timer_start     
* Description :  
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void right_refresh_timer_start(int ms)
{

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

/*********************************************************************************
* function   :   refresh_timer_stop     
* Description :  
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 10.18
**********************************************************************************/	
void right_refresh_timer_stop(void)
{
    xTimerStop(right_display_timer, 0);   //停止定时器
}



bool left_refresh_timer_isActive()
{
    if(xTimerIsTimerActive(left_display_timer) != pdFALSE)
    {
        return true;
    }else
    {
        return false;
    }

}


bool right_refresh_timer_isActive()
{
    if(xTimerIsTimerActive(right_display_timer) != pdFALSE)
    {
        return true;
    }else
    {
        return false;
    }

}


	









static const char *LOG_TAG = "EPD";

#if HARDWARE_SPI


spi_device_handle_t epd_spi;

        // uint8_t cmd[1]={0};
        // epd_write_cmd(screen,0x00,false);
        // cmd[0] = 0x17;
        // epd_write_data(screen,cmd,1);


//Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA.
DRAM_ATTR static const epd_init_cmd_t init_cmds[]={
    {0x00,{0x1f,0x0E},2},
    {0x50,{0x18,0x07},2},
    {0xe0,{0x02},1},
    {0xe5,{0x5c},1},
    {0x11, {0}, 0x80},
    #if 0
    {0x00,{0x1B},1},
    #else
    //{0x00,{0x8F},1},
    #endif


    {0, {0}, 0xff},
};
//This function is called (in irq context!) just before a transmission starts. It will
//set the D/C line to the value indicated in the user field.
static void spi_pre_transfer_callback(spi_transaction_t *t)
{
    int dc=(int)t->user;
    gpio_set_level(PIN_L_DC, dc);
    gpio_set_level(PIN_R_DC, dc);
}


#if 0
void epd_spi_write(struct EPD_INFO_SET* epd_pin_set,unsigned char value)
{
    int i = 0,data = value;
    epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL);

    for(i=0;i<8;i++)
    {
        if(data&0x0080)
        {
            epd_set_level(epd_pin_set->sda_pin,HIGH_LEVEL);
        }
        else
        {
            epd_set_level(epd_pin_set->sda_pin,LOW_LEVEL);
        }

        // ets_delay_us(1);
        epd_set_level(epd_pin_set->sclk_pin, HIGH_LEVEL);
        // ets_delay_us(1);
        epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL);
        
        data = ((data)<<1 & 0xff);
    }

}

#endif





/*********************************************************************************
* function   :   SPI_Write     
* Description :  spi写入数据
* Input       :  
* Output      :  
* Author      :  祁鑫                  Data : 2023 8.11
**********************************************************************************/	
IRAM_ATTR void SPI_Write(unsigned char value)                                    
{
    int i=0,data=value;   
    int j = 100;
    gpio_set_level(PIN_SPI_CLK, 0);
    for(i=0;i<8;i++)
    {
      if(data&0x0080)
      {
         gpio_set_level(PIN_SPI_MOSI, 1);
        //EPD_SDA_1;
      }else
      {
         gpio_set_level(PIN_SPI_MOSI, 0);
        //EPD_SDA_0;
      }
      //vTaskDelay(1/ portTICK_PERIOD_MS);
      gpio_set_level(PIN_SPI_CLK, 1);
      //vTaskDelay(1/ portTICK_PERIOD_MS);
      gpio_set_level(PIN_SPI_CLK, 0);
      data=((data<<1)&0xff);
    }
}





//Initialize the display
void epd_init(void)
{
    #if !SOFTWARE_SPI_ENABLE    //硬件spi
    esp_err_t ret;

    spi_bus_config_t buscfg={
        .miso_io_num=-1,
        .mosi_io_num=PIN_SPI_MOSI,
        .sclk_io_num=PIN_SPI_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=4096//dma
    };
    spi_device_interface_config_t devcfg={
        .clock_speed_hz=20*1000*1000,           //Clock out at 10 MHz
        .mode=0,                                //SPI mode 0
        .spics_io_num=-1,                       //CS pin
        .queue_size=7,                          //We want to be able to queue 7 transactions at a time
        .pre_cb=spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };

    //Initialize the SPI bus
    ret=spi_bus_initialize(EPD_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);

    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(EPD_HOST, &devcfg, &epd_spi);
    ESP_ERROR_CHECK(ret);

    #else    //软件模拟spi




    gpio_reset_pin(PIN_SPI_MOSI);
    gpio_reset_pin(PIN_SPI_CLK);
    gpio_reset_pin(PIN_L_CS);

    gpio_reset_pin(PIN_L_DC);
    gpio_reset_pin(PIN_L_RST);
    gpio_reset_pin(PIN_L_BUSY);

    gpio_reset_pin(PIN_R_CS);
    gpio_reset_pin(PIN_R_DC);
    gpio_reset_pin(PIN_R_RST);
    gpio_reset_pin(PIN_R_BUSY);
    #endif



    //gpio_reset_pin(PIN_L_CS);





    //Initialize non-SPI GPIOs
    gpio_config_t io_conf = {};
    io_conf.pin_bit_mask = PIN_EPD_OUTPUT;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);


    io_conf.pin_bit_mask = PIN_EPD_INPUT;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);

    //Reset the display


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

    gpio_set_level(PIN_L_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_L_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);

    gpio_set_level(PIN_R_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_R_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);

    #if 1
        int cmd=0;
        //Send all the commands
        while (init_cmds[cmd].databytes!=0xff) {

            #if 1
            epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false);
            epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);

            epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false);
            epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);
            #endif
            if (init_cmds[cmd].databytes&0x80) {
                vTaskDelay(100 / portTICK_PERIOD_MS);
            }
            cmd++;
        }
    #endif
}

#if QUICK_DISPLAY
uint8_t *old_buffer= heap_caps_malloc(480*81, MALLOC_CAP_8BIT);
memset(old_buffer,0X00,480*81);
epd_cache_quick_full_screen_refresh(SCREEN_LEFT,NULL,old_buffer);
epd_write_cmd(SCREEN_LEFT,0x04,false); //POWER ON
epd_check_status(SCREEN_LEFT);       //waiting for the electronic paper IC to release the idle signal
//Refresh
epd_refresh(SCREEN_LEFT);
epd_write_cmd(SCREEN_LEFT,0x02,false);  // Power OFF 
epd_check_status(SCREEN_LEFT);

epd_sleep(SCREEN_LEFT);

free(old_buffer);
#else

#endif




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


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



  
}




void epd_init_cmd(screen_t screen)
{


if(  screen ==  SCREEN_LEFT) 
{
    gpio_set_level(PIN_L_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_L_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);



     int cmd=0;
    //Send all the commands
    while (init_cmds[cmd].databytes!=0xff) {

        #if 1
        epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);

       
        #endif
        if (init_cmds[cmd].databytes&0x80) {
            vTaskDelay(10 / portTICK_PERIOD_MS);
        }
        cmd++;
    }



}

if( screen ==  SCREEN_RIGHT) 
{
    gpio_set_level(PIN_R_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_R_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);


    int cmd=0;
    //Send all the commands
    while (init_cmds[cmd].databytes!=0xff) {

        #if 1
        epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);
        #endif
        if (init_cmds[cmd].databytes&0x80) {
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
        cmd++;
    }

}


  

}

static void spi_get_result(spi_device_handle_t spi)
{
    spi_transaction_t *rtrans = NULL;
    esp_err_t ret;
    spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
    //assert(ret==ESP_OK);
}


void epd_cmd(spi_device_handle_t spi, const uint8_t cmd, bool keep_cs_active)
{
    #if !SOFTWARE_SPI_ENABLE
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length=8;                     //Command is 8 bits
    t.tx_buffer=&cmd;               //The data is the cmd itself
    t.user=(void*)0;                //D/C needs to be set to 0
    if (keep_cs_active) {
      t.flags = SPI_TRANS_CS_KEEP_ACTIVE;   //Keep CS active after data transfer
    }
    ret=spi_device_queue_trans(spi, &t, portMAX_DELAY);
    // assert(ret==ESP_OK);            //Should have had no issues.
    spi_get_result(spi);
    #else
    SPI_Write(cmd);    

    #endif
}



void epd_data(spi_device_handle_t spi, const uint8_t *data, int len)
{
    #if !SOFTWARE_SPI_ENABLE
    esp_err_t ret;
    spi_transaction_t t;
    int i;
    if (len==0) return;             //no need to send anything
    if(len > SPI_MAX_LEN)
    {
        for(i=0;i<len;i=i+SPI_MAX_LEN)
        {
            memset(&t, 0, sizeof(t));       //Zero out the transaction
            t.length=SPI_MAX_LEN*8;                 //Len is in bytes, transaction length is in bits.
            t.tx_buffer=data+i;               //Data
            t.user=(void*)1;                //D/C needs to be set to 1
            ret=spi_device_queue_trans(spi, &t, portMAX_DELAY);  //Transmit!
            // assert(ret==ESP_OK);            //Should have had no issues.
            if(ret != ESP_OK)
            {
                printf("spi_device_queue_trans err:ret =%d",ret);
            }
            spi_get_result(spi);
        }
            i-=SPI_MAX_LEN;
            memset(&t, 0, sizeof(t));       //Zero out the transaction
            t.length=(len-i)*8;                 //Len is in bytes, transaction length is in bits.
            t.tx_buffer=data+i;               //Data
            t.user=(void*)1;                //D/C needs to be set to 1
            ret=spi_device_queue_trans(spi, &t, portMAX_DELAY);  //Transmit!
            // assert(ret==ESP_OK);            //Should have had no issues.
            if(ret != ESP_OK)
            {
                printf("spi_device_queue_trans err:ret =%d",ret);
            }
            spi_get_result(spi);
        return;
    }

    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length=len*8;                 //Len is in bytes, transaction length is in bits.
    t.tx_buffer=data;               //Data
    t.user=(void*)1;                //D/C needs to be set to 1
    ret=spi_device_queue_trans(spi, &t, portMAX_DELAY);  //Transmit!
    // assert(ret==ESP_OK);            //Should have had no issues.
                if(ret != ESP_OK)
            {
                printf("spi_device_queue_trans err:ret =%d",ret);
            }
    spi_get_result(spi);
    #else

    {
         for(int i = 0;i<len;i++)
        {
              SPI_Write(data[i]);    
        }

    }
    
      


    #endif
}



void epd_write_cmd(screen_t screen, unsigned char command,bool keep_cs_active)
{
    if(screen == SCREEN_LEFT)
    {
		gpio_set_level(PIN_R_CS,1);
        gpio_set_level(PIN_L_CS,0);
        
        gpio_set_level(PIN_L_DC, 0);

        epd_cmd(epd_spi, command, keep_cs_active);
		gpio_set_level(PIN_R_CS,1);
        gpio_set_level(PIN_L_CS,1);
        
    }
    else if(screen == SCREEN_RIGHT)
    {
		gpio_set_level(PIN_L_CS,1);
        gpio_set_level(PIN_R_CS,0);
        
        gpio_set_level(PIN_R_DC, 0);
        epd_cmd(epd_spi, command, keep_cs_active);
		gpio_set_level(PIN_L_CS,1);
        gpio_set_level(PIN_R_CS,1);
        
    }
    else
    {
        ESP_LOGE(LOG_TAG,"cmd err:screen");
    }
}
void epd_write_data(screen_t screen, const uint8_t *data, int len)
{
    if(screen == SCREEN_LEFT)
    {
		gpio_set_level(PIN_R_CS,1);
        gpio_set_level(PIN_L_CS,0);
        
        gpio_set_level(PIN_L_DC, 1);
        epd_data(epd_spi, data, len);
        gpio_set_level(PIN_L_CS,1);
    }
    else if(screen == SCREEN_RIGHT)
    {
		gpio_set_level(PIN_L_CS,1);
        gpio_set_level(PIN_R_CS,0);
        
        gpio_set_level(PIN_R_DC, 1);
        epd_data(epd_spi, data, len);
        gpio_set_level(PIN_R_CS,1);
    }
    else
    {
        ESP_LOGE(LOG_TAG,"data err:screen");
    }
}
bool epd_check_status(screen_t screen)
{

    #if 0
    if(screen == SCREEN_LEFT)
    {
        while(!gpio_get_level(PIN_L_BUSY))
        {

        };
    }
    else if(screen == SCREEN_RIGHT)
    {
        while(!gpio_get_level(PIN_R_BUSY));
    }
    else
    {
        ESP_LOGE(LOG_TAG,"check err:screen");
    }
    #else
    
	int count = 0;
	unsigned char busy;
    int64_t t_after_us = 0;
    int64_t t_before_us = esp_timer_get_time();
	// while(1)
	{

		//=1 BUSY
        if(screen == SCREEN_LEFT)
        {
            while(1)
            {
               
                busy = gpio_get_level(PIN_L_BUSY);
                busy = (busy & 0x01);        
                if(busy==1) 
                {
                    // printf("left lcd idle\r\n");
                    break;
                }      
#if 0
            vTaskDelay(10 / portTICK_PERIOD_MS);  
                            count ++;
            if(count >= 200){
            printf("l---------------time out ---\n");
                break;                  
            }   
#else
        t_after_us = esp_timer_get_time();
        if((t_after_us-t_before_us)>1000*1000)
        {
            printf("t_before_us =%lld ,t_after_us = %lld\n",t_before_us,t_after_us);
            return 0;
            break;  
        }
#endif

            }




        }
        else if(screen == SCREEN_RIGHT)
        {
            //while(!gpio_get_level(PIN_R_BUSY));

                while(1)
            {
                busy = gpio_get_level(PIN_R_BUSY);
                busy = (busy & 0x01);        
                if(busy==1) 
                {
                    // printf("right lcd idle\r\n");
                    break;
                }        
#if 0 
                vTaskDelay(10 / portTICK_PERIOD_MS);  
                                count ++;
                if(count >= 200){
                printf("r---------------time out ---\n");
                 break;                  
                }
#else
        t_after_us = esp_timer_get_time();
        if((t_after_us-t_before_us)>1000*1000)
        {
            printf(" r t_before_us =%lld ,t_after_us = %lld\n",t_before_us,t_after_us);
            return 0;
            break;  
        }
#endif

            }
        }
        else
        {
            ESP_LOGE(LOG_TAG,"check err:screen");
        }

	}  

    #endif
    return 1;
}











void deepsleep_epd_check_status(screen_t screen)
{

    if(screen == SCREEN_LEFT)
    {
        while(!gpio_get_level(PIN_L_BUSY));
    }
    else if(screen == SCREEN_RIGHT)
    {
        while(!gpio_get_level(PIN_R_BUSY));
    }
    else
    {
        ESP_LOGE(LOG_TAG,"check err:screen");
    }
  
}


void epd_check_power_off(screen_t screen)
{

     if(screen == SCREEN_LEFT)
    {
        while(gpio_get_level(PIN_L_BUSY))
        {
             vTaskDelay(20 / portTICK_PERIOD_MS); 
             printf("left power off\r\n");
        }
    }
    else if(screen == SCREEN_RIGHT)
    {
        while(gpio_get_level(PIN_R_BUSY))
        {
             vTaskDelay(20 / portTICK_PERIOD_MS); 
             printf("right power off\r\n");
        }
    }
    else
    {
        ESP_LOGE(LOG_TAG,"check err:screen");
    }
}


void epd_check_power_on(screen_t screen)
{

     if(screen == SCREEN_LEFT)
    {
    
        while(gpio_get_level(PIN_L_BUSY))
        {
            printf("left power on\r\n");
        }
    }
    else if(screen == SCREEN_RIGHT)
    {
        while(gpio_get_level(PIN_R_BUSY))
        {
             printf("right power on\r\n");
        }
    }
    else
    {
        ESP_LOGE(LOG_TAG,"check err:screen");
    }
}




void epd_refresh(screen_t screen)
{
    epd_write_cmd(screen,0x12,false);//DISPLAY REFRESH  
    //ets_delay_us(200); //!!!The delay here is necessary, 200uS at least!!!
    //vTaskDelay(1 / portTICK_PERIOD_MS);
    epd_check_status(screen); //waiting for the electronic paper  
}
void epd_sleep(screen_t screen)
{

    //printf("SLEEP SCREEN =%d\r\n",screen);
 
 #if 0
    epd_write_cmd(screen,0x04,false);  // Power ON 
    
    epd_check_power_on(screen);

  #endif  
    //epd_check_status(screen);

    //epd_refresh(screen);

    uint8_t tmp = 0xa5;
    epd_write_cmd(screen,0x07,false);
    epd_write_data(screen,&tmp,1);
    

   


    //vTaskDelay(20 / portTICK_PERIOD_MS);
#if 0
    epd_write_cmd(screen,0x02,false);  // Power OFF
     vTaskDelay(20 / portTICK_PERIOD_MS); 
     epd_check_power_off(screen);
#endif
    #if 1 
    //epd_write_cmd(screen,0x02,false); // Power OFF 
    //epd_check_status(screen);
    #endif
}

IRAM_ATTR void epd_display(screen_t screen,const unsigned char* picData)
{

    #if SOFTWARE_SPI_ENABLE
    if(screen == SCREEN_LEFT)
    {
         left_refresh_complete = false;   
    }


    if(screen == SCREEN_RIGHT)
    {
        right_refresh_complete = false;
    }

    #endif


    epd_write_cmd(screen,0x13,false);
    epd_check_status(screen);
    epd_write_data(screen,picData,38880);
    epd_check_status(screen);
    epd_write_cmd(screen,0x04,false); //POWER ON
    epd_check_status(screen);       //waiting for the electronic paper IC to release the idle signal
    //Refresh
    epd_refresh(screen);

    epd_write_cmd(screen,0x02,false);  // Power OFF 
    epd_check_status(screen);
    epd_sleep(screen);



#if SOFTWARE_SPI_ENABLE
    current_display = screen;
    //vTaskDelay(0000 / portTICK_PERIOD_MS);


  if(screen == SCREEN_LEFT)
  {
    left_refresh_timer_start(2000);
  }


  if(screen == SCREEN_LEFT)
  {
    right_refresh_timer_start(2000);
  }
#else
 current_display = screen;
    //vTaskDelay(0000 / portTICK_PERIOD_MS);


  if(screen == SCREEN_LEFT)
  {
    left_refresh_timer_start(2000);
  }


  if(screen == SCREEN_LEFT)
  {
    right_refresh_timer_start(2000);
  }

#endif

}
#if 1
void epd_cache(screen_t screen,const unsigned char* picData)
{
    epd_write_cmd(screen,0x13,false);
    epd_write_data(screen,picData,38880);
}

void epd_cache_quick_full_screen_refresh(screen_t screen,const unsigned char* old,const unsigned char* new)
{

if((screen == SCREEN_LEFT)&&(old!=NULL))
{
    printf("left quick\r\n");
    //Reset the display
    gpio_set_level(PIN_L_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_L_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);

    uint8_t cmd[1]={0};
    epd_write_cmd(screen,0x00,false);
    cmd[0] = 0x1F;
    epd_write_data(screen,cmd,1);
#if  0

        uint8_t cmd[1]={0};

        epd_write_cmd(screen,0x61,false);
        cmd[0] = 0xF0;
        epd_write_data(screen,cmd,1);
        cmd[0] = 0x01;
        epd_write_data(screen,cmd,1);

        cmd[0] = 0xA0;
        epd_write_data(screen,cmd,1);
 #endif       
#if 0
    int cmd=0;
    //Send all the commands
    while (init_cmds[cmd].databytes!=0xff) {
        epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);

        epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);
        if (init_cmds[cmd].databytes&0x80) {
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
        cmd++;
    }
#endif
}

if((screen == SCREEN_RIGHT)&&(old!=NULL))
{

     printf("right quick\r\n");
    gpio_set_level(PIN_R_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_R_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);


        // uint8_t cmd[1]={0};
        // epd_write_cmd(screen,0x00,false);
        // cmd[0] = 0x1F;
        // epd_write_data(screen,cmd,1);

#if 0
        uint8_t cmd[1]={0};

        epd_write_cmd(screen,0x61,false);
        cmd[0] = 0xF0;
        epd_write_data(screen,cmd,1);
        cmd[0] = 0x01;
        epd_write_data(screen,cmd,1);

        cmd[0] = 0xA0;
        epd_write_data(screen,cmd,1);
 #endif       
    #if 0
    int cmd=0;
    //Send all the commands
    while (init_cmds[cmd].databytes!=0xff) {
        epd_write_cmd(SCREEN_LEFT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_LEFT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);

        epd_write_cmd(SCREEN_RIGHT, init_cmds[cmd].cmd, false);
        epd_write_data(SCREEN_RIGHT, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);
        if (init_cmds[cmd].databytes&0x80) {
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
        cmd++;
    }

    #endif

}

    if (old !=NULL)
    {

         epd_write_cmd(screen,0x10,false);
         epd_check_status(screen);
         epd_write_data(screen,old,38880);
    }
    
    #if 0
        uint8_t cmd[1]={0};
        epd_write_cmd(screen,0x61,false);
        cmd[0] = 0xF0;
        epd_write_data(screen,cmd,1);
        cmd[0] = 0x01;
        epd_write_data(screen,cmd,1);

        cmd[0] = 0xA0;
        epd_write_data(screen,cmd,1);
    #endif    


    epd_write_cmd(screen,0x13,false);
    epd_write_data(screen,new,38880);
}
#endif
void epd_display_partal(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
                         screen_t screen,const unsigned char* picData)
{
    unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(screen,0x91,false);   // partial in
    epd_check_status(screen);
        
    epd_write_cmd(screen,0x90,false);
    epd_check_status(screen);

    epd_write_data(screen,&Xstart_H,1);
    epd_write_data(screen,&Xstart_L,1);

    epd_write_data(screen,&Xend_H,1);
    epd_write_data(screen,&Xend_L,1);

    epd_write_data(screen,&Ystart_H,1);
    epd_write_data(screen,&Ystart_L,1);

    epd_write_data(screen,&Yend_H,1);
    epd_write_data(screen,&Yend_L,1);
uint8_t tmp = 0x01;
    epd_write_data(screen,&tmp,1);

    epd_write_cmd(screen,0x13,false);
    epd_check_status(screen);
 


    epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart)/8));

    epd_write_cmd(screen,0x92,false); 
 
    epd_write_cmd(screen,0x04,false);  // Power ON 
    epd_check_status(screen);

    epd_refresh(screen);

    epd_write_cmd(screen,0x02,false);  // Power OFF 
    epd_check_status(screen);
}

void epd_partial_cache(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
                         screen_t screen,const unsigned char* picData)
{
     unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(screen,0x91,false);   // partial in
    epd_check_status(screen);
        
    epd_write_cmd(screen,0x90,false);
    epd_check_status(screen);

    epd_write_data(screen,&Xstart_H,1);
    epd_write_data(screen,&Xstart_L,1);

    epd_write_data(screen,&Xend_H,1);
    epd_write_data(screen,&Xend_L,1);

    epd_write_data(screen,&Ystart_H,1);
    epd_write_data(screen,&Ystart_L,1);

    epd_write_data(screen,&Yend_H,1);
    epd_write_data(screen,&Yend_L,1);
    uint8_t tmp = 0x01;
    epd_write_data(screen,&tmp,1);

    epd_write_cmd(screen,0x13,false);
    epd_check_status(screen);
 
    epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart)/8));

    epd_write_cmd(screen,0x92,false); 
}


void epd_cache_quick_partial_screen_refresh(screen_t screen,uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,const unsigned char* old,const unsigned char* new)
{

if((screen == SCREEN_LEFT)&&(old!=NULL))
{
    printf("left partial quick\r\n");
    //Reset the display
    gpio_set_level(PIN_L_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_L_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);

    uint8_t cmd[1]={0};
    epd_write_cmd(screen,0x00,false);
    cmd[0] = 0x1F;
    epd_write_data(screen,cmd,1);   
}

if((screen == SCREEN_RIGHT)&&(old!=NULL))
{
    printf("right partial quick\r\n");
    gpio_set_level(PIN_R_RST, 0);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    gpio_set_level(PIN_R_RST, 1);
    vTaskDelay(10 / portTICK_PERIOD_MS);
}

#if 0
    if (old !=NULL)
    {

         epd_write_cmd(screen,0x10,false);
         epd_write_data(screen,old,38880);
    }
    epd_write_cmd(screen,0x13,false);
    epd_write_data(screen,new,38880);
#endif






     unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(screen,0x91,false);   // partial in
    epd_check_status(screen);
        
    epd_write_cmd(screen,0x90,false);
    epd_check_status(screen);

    epd_write_data(screen,&Xstart_H,1);
    epd_write_data(screen,&Xstart_L,1);

    epd_write_data(screen,&Xend_H,1);
    epd_write_data(screen,&Xend_L,1);

    epd_write_data(screen,&Ystart_H,1);
    epd_write_data(screen,&Ystart_L,1);

    epd_write_data(screen,&Yend_H,1);
    epd_write_data(screen,&Yend_L,1);
    uint8_t tmp = 0x01;
    epd_write_data(screen,&tmp,1);

// epd_write_cmd(screen,0x13,false);
// epd_check_status(screen);
 
 printf("1\r\n");
if (old !=NULL)
{
printf("2\r\n");
    epd_write_cmd(screen,0x10,false);
    epd_check_status(screen);
    epd_write_data(screen,old,((Yend - Ystart)*(Xend - Xstart)/8));
    epd_write_cmd(screen,0x92,false); 
}
printf("3\r\n");
    epd_write_cmd(screen,0x13,false);
    epd_check_status(screen);
    epd_write_data(screen,new,((Yend - Ystart)*(Xend - Xstart)/8));
    epd_write_cmd(screen,0x92,false); 

}






static uint8_t get_data(uint8_t * color, uint8_t pix_size)
{
    uint8_t data = 0;
    int i =0, j = 0;
    for (i = 0; i < 8; i++) {
        data = data | (color[j] << (7-i));
        j = j + pix_size;
    }
    return data;
}


void epd_partial_cache1(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
                         screen_t screen,const unsigned char* picData)
{
     unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(screen,0x91,false);   // partial in
    epd_check_status(screen);
        
    epd_write_cmd(screen,0x90,false);
    epd_check_status(screen);

    epd_write_data(screen,&Xstart_H,1);
    epd_write_data(screen,&Xstart_L,1);

    epd_write_data(screen,&Xend_H,1);
    epd_write_data(screen,&Xend_L,1);

    epd_write_data(screen,&Ystart_H,1);
    epd_write_data(screen,&Ystart_L,1);

    epd_write_data(screen,&Yend_H,1);
    epd_write_data(screen,&Yend_L,1);
    uint8_t tmp = 0x01;
    epd_write_data(screen,&tmp,1);

    epd_write_cmd(screen,0x13,false);
    epd_check_status(screen);

    #if 0
    epd_write_data(screen,picData,((Yend - Ystart)*(Xend - Xstart)));
    #else
   uint8_t data;
    //     disp_drv.hor_res = 648;
    // disp_drv.ver_res = 480;
    for (int i = 480 - 1; i >=0 ; i--) {
        for (int j = 0; j < 648; ) {
            data = get_data(&picData[j + i * 648 * 1], 1);
            //printf("%02x",data);
            epd_write_data(screen,&data,1);

            j = j + 8 * 1;
        }
    }
    #endif

    epd_write_cmd(screen,0x92,false); 
}

void epd_powerOn_refresh(screen_t screen)
{
    epd_write_cmd(screen,0x04,false);   // Power ON 
    epd_check_status(screen);

    epd_refresh(screen);

    epd_write_cmd(screen,0x02,false); // Power OFF 
    epd_check_status(screen);
}


// 定义最大重复计数
#define MAX_REPEAT 255

// 压缩函数
unsigned int compressRLE(uint8_t *input, unsigned int size, uint8_t *output) {
    unsigned int i = 0;
    unsigned int outputSize = 0;
    while (i < size) {
        uint8_t current = input[i];
        unsigned int count = 1;
        i++;
        while (i < size && input[i] == current && count < MAX_REPEAT) {
            count++;
            i++;
        }
        // 输出像素值和计数值到output
        output[outputSize++] = current;
        output[outputSize++] = count;
    }
    return outputSize;
}

// 解压函数
unsigned int decompressRLE(uint8_t *input, unsigned int size, uint8_t *output) {
    unsigned int i = 0;
    unsigned int outputSize = 0;
    while (i < size) {
        uint8_t current = input[i];
        i++;
        unsigned int count = input[i];
        i++;
        // 输出像素值count次到output
        for (unsigned int j = 0; j < count; j++) {
            output[outputSize++] = current;
        }
    }
    return outputSize;
}


void test()
{

    // 定义图像数据（十六进制数组）
    uint8_t imageData[] = {0x12, 0x12, 0x12, 0x13, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15};


 int imageSize = sizeof(imageData) / sizeof(imageData[0]);

    printf("原始图像数据：\n");
    for (int i = 0; i < imageSize; i++) {
        printf("0x%02X ", imageData[i]);
    }
    printf("\n");

    uint8_t compressedData[2 * imageSize]; // 假设压缩后的数据不会超过原数据的两倍大小
    uint8_t decompressedData[imageSize]; // 假设解压后的数据不会超过原数据大小

    printf("压缩后的数据：\n");
    int compressedSize = compressRLE(imageData, imageSize, compressedData);
    for (int i = 0; i < compressedSize; i++) {
        printf("0x%02X ", compressedData[i]);
    }
    printf("\n");

    printf("解压后的数据：\n");
    int decompressedSize = decompressRLE(compressedData, compressedSize, decompressedData);
    for (int i = 0; i < decompressedSize; i++) {
        printf("0x%02X ", decompressedData[i]);
    }
    printf("\n");

    printf("压缩后的数据大小：%d 字节\n", compressedSize);
    printf("解压后的数据大小：%d 字节\n", decompressedSize);



}
// uint8_t tmp[38880];
IRAM_ATTR bool epd_cache_quick(screen_t screen,const unsigned char* old,const unsigned char* new)
{
 bool ret = false;
    #if SOFTWARE_SPI_ENABLE
    if(screen == SCREEN_LEFT)
    {
         left_refresh_complete = false;   
    }

    if(screen == SCREEN_RIGHT)
    {
        right_refresh_complete = false;
    }
    #else

    if(screen == SCREEN_LEFT)
    {
         left_refresh_complete = false;   
    }

    if(screen == SCREEN_RIGHT)
    {
        right_refresh_complete = false;
    }


    #endif

    if((screen == SCREEN_LEFT)&&(old!=NULL))
    {
        printf("left partial quick\r\n");
        //Reset the display
        gpio_set_level(PIN_L_RST, 0);
        vTaskDelay(10 / portTICK_PERIOD_MS);
        gpio_set_level(PIN_L_RST, 1);
        vTaskDelay(10 / portTICK_PERIOD_MS);
        ret = epd_check_status(screen);
    if(!ret)
    {
        printf("err:2busy ！！！！！\n");
        goto err;
    }

        uint8_t cmd[1]={0};
        epd_write_cmd(screen,0x00,false);
        cmd[0] = 0x1F;
        epd_write_data(screen,cmd,1);   
    }

    if((screen == SCREEN_RIGHT)&&(old!=NULL))
    {
        printf("right partial quick\r\n");
        gpio_set_level(PIN_R_RST, 0);
        vTaskDelay(10 / portTICK_PERIOD_MS);
        gpio_set_level(PIN_R_RST, 1);
        vTaskDelay(10 / portTICK_PERIOD_MS);
     ret = epd_check_status(screen);
         if(!ret)
    {
        printf("err:3busy ！！！！！\n");
        goto err;
    }
        uint8_t cmd2[1]={0};
        epd_write_cmd(screen,0x00,false);
        cmd2[0] = 0x1F;
        epd_write_data(screen,cmd2,1);
    }
#if 1
    if (old !=NULL)
    {
        epd_write_cmd(screen,0x10,false);
        ret = epd_check_status(screen);
        if(!ret)
        {
            printf("err:busy ！！！！！\n");
            goto err;
        }
        epd_write_data(screen,old,38880);
        ret = epd_check_status(screen);
        if(!ret)
        {
            printf("err:2busy ！！！！！\n");
            goto err;
        }
    }
#else
        epd_write_cmd(screen,0x10,false);
        epd_check_status(screen);
        memcpy(&tmp,new,38880);
        for(int i=0;i<38880;i++)
        {
            tmp[i] = ~tmp[i];
        }
        epd_write_data(screen,&tmp,38880);
#endif
    epd_write_cmd(screen,0x13,false);
    ret = epd_check_status(screen);
    if(!ret)
    {
        printf("err:2busy ！！！！！\n");
        goto err;
    }
    epd_write_data(screen,new,38880);
    ret = epd_check_status(screen);
    if(!ret)
    {
        printf("err:2busy ！！！！！\n");
        goto err;
    }
	


#if 0
        if(screen == SCREEN_LEFT)
    {
         left_refresh_complete = true;   
    }


    if(screen == SCREEN_RIGHT)
    {
        right_refresh_complete = true;
    }
#else

#if SOFTWARE_SPI_ENABLE
    current_display = screen;
    //vTaskDelay(0000 / portTICK_PERIOD_MS);
  if(screen == SCREEN_LEFT)
  {
    left_refresh_timer_start(1000);
  }


  if(screen == SCREEN_LEFT)
  {
    right_refresh_timer_start(1000);
  }
 #else
      current_display = screen;
    //vTaskDelay(0000 / portTICK_PERIOD_MS);
  if(screen == SCREEN_LEFT)
  {
    left_refresh_timer_start(500);
  }


  if(screen == SCREEN_LEFT)
  {
    right_refresh_timer_start(500);
  }

#endif



    //vTaskDelay(0000 / portTICK_PERIOD_MS);
    //refresh_timer_start(500);
    //xTimerStart(slow_display_timer, 0); //开始定时器


#endif
    return true;
    err:
    ESP_LOGE(LOG_TAG,"err:epd_check_status");
    return false;
}
void epd_powerOn_refresh_sleep(screen_t screen)
{
    epd_write_cmd(screen,0x04,false);   // Power ON 
    epd_check_status(screen);

    epd_refresh(screen);
    epd_sleep(screen);
}




void deepsleep_epd_powerOn_refresh_sleep(screen_t screen)
{
    epd_write_cmd(screen,0x04,false);   // Power ON 
    //epd_check_status(screen);
    deepsleep_epd_check_status(screen);

    epd_write_cmd(screen,0x12,false);//DISPLAY REFRESH  
    deepsleep_epd_check_status(screen);
    //epd_refresh(screen);
    //epd_sleep(screen);
}




#else/*HAREWARE_SPI*/

static void task_delay_ms(uint32_t ms_count)
{
    vTaskDelay(ms_count / portTICK_PERIOD_MS);
}

void epd_pin_init(struct EPD_INFO_SET* epd_pin_set)
{
    esp_log_level_set("gpio",ESP_LOG_NONE);//close gpio logging
    ESP_LOGI(LOG_TAG,"epd_pin_init");
    #define EPD_OUT_PIN_SEL ((1ULL<<epd_pin_set->sclk_pin)|\
                        (1ULL<<epd_pin_set->sda_pin)|\
                        (1ULL<<epd_pin_set->res_pin)|\
                        (1ULL<<epd_pin_set->dc_pin)|\
                        (1ULL<<epd_pin_set->cs_pin))

    #define EPD_IN_PIN_SEL  (1ULL<<epd_pin_set->busy_pin)


    gpio_config_t epd_pin_cfg = {};

    epd_pin_cfg.intr_type = GPIO_INTR_DISABLE;
    epd_pin_cfg.mode = GPIO_MODE_OUTPUT;
    epd_pin_cfg.pin_bit_mask =EPD_OUT_PIN_SEL;
    epd_pin_cfg.pull_down_en = 0;
    epd_pin_cfg.pull_up_en = 0;
    gpio_config(&epd_pin_cfg);

    epd_pin_cfg.intr_type = GPIO_INTR_DISABLE;
    epd_pin_cfg.mode = GPIO_MODE_INPUT;
    epd_pin_cfg.pin_bit_mask =EPD_IN_PIN_SEL;
    epd_pin_cfg.pull_down_en = 0;
    epd_pin_cfg.pull_up_en = 1;
    gpio_config(&epd_pin_cfg);
    esp_log_level_set("gpio",LOG_LOCAL_LEVEL);

}

void epd_spi_write(struct EPD_INFO_SET* epd_pin_set,unsigned char value)
{
    int i = 0,data = value;
    epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL);

    for(i=0;i<8;i++)
    {
        if(data&0x0080)
        {
            epd_set_level(epd_pin_set->sda_pin,HIGH_LEVEL);
        }
        else
        {
            epd_set_level(epd_pin_set->sda_pin,LOW_LEVEL);
        }

        // ets_delay_us(1);
        epd_set_level(epd_pin_set->sclk_pin, HIGH_LEVEL);
        // ets_delay_us(1);
        epd_set_level(epd_pin_set->sclk_pin, LOW_LEVEL);
        
        data = ((data)<<1 & 0xff);
    }

}

void epd_write_cmd(struct EPD_INFO_SET* epd_pin_set, unsigned char command)
{
    epd_set_level(epd_pin_set->cs_pin, LOW_LEVEL);
    epd_set_level(epd_pin_set->dc_pin, LOW_LEVEL);
    epd_spi_write(epd_pin_set,command);
    epd_set_level(epd_pin_set->cs_pin, HIGH_LEVEL);
}

void epd_write_data(struct EPD_INFO_SET* epd_pin_set, unsigned char command)
{
    epd_set_level(epd_pin_set->cs_pin, LOW_LEVEL);
    epd_set_level(epd_pin_set->dc_pin, HIGH_LEVEL);
    epd_spi_write(epd_pin_set,command);
    epd_set_level(epd_pin_set->cs_pin, HIGH_LEVEL);
    //ets_delay_us(2);
}
void epd_init(struct EPD_INFO_SET* epd_pin_set)
{
    epd_set_level(epd_pin_set->res_pin, LOW_LEVEL);
    task_delay_ms(10);
    epd_set_level(epd_pin_set->res_pin, HIGH_LEVEL);
    task_delay_ms(10);
}

void epd_check_status(struct EPD_INFO_SET* epd_pin_set)
{
    while(!epd_get_level(epd_pin_set->busy_pin));
}

void epd_refresh(struct EPD_INFO_SET* epd_pin_set)
{
    epd_write_cmd(epd_pin_set,0x12);//DISPLAY REFRESH  
    //ets_delay_us(200); //!!!The delay here is necessary, 200uS at least!!!
    task_delay_ms(1);
    epd_check_status(epd_pin_set); //waiting for the electronic paper  
}

void epd_sleep(struct EPD_INFO_SET* epd_pin_set)
{
    epd_write_cmd(epd_pin_set,0x07);
    epd_write_data(epd_pin_set,0xa5);
}

void epd_screen_init(struct EPD_INFO_SET* epd_pin_set)
{
    epd_pin_init(epd_pin_set);


    epd_init(epd_pin_set);

    epd_write_cmd(epd_pin_set,0x00);
    epd_write_data(epd_pin_set,0x1f);
    epd_write_data(epd_pin_set,0x09);

    epd_write_cmd(epd_pin_set,0x50);
    epd_write_data(epd_pin_set,0x18);
    epd_write_data(epd_pin_set,0x07);

    epd_write_cmd(epd_pin_set,0xe0);
    epd_write_data(epd_pin_set,0x02);

    epd_write_cmd(epd_pin_set,0xe5);
    epd_write_data(epd_pin_set,0x5c);

}
void epd_clear_black(struct EPD_INFO_SET* epd_pin_set)
{
    unsigned int i;
  
    epd_write_cmd(epd_pin_set,0x13);
    for(i=0;i<38880;i++)       
    {   
        epd_write_data(epd_pin_set,0xff);  
    }

    epd_write_cmd(epd_pin_set,0x04); //POWER ON
    epd_check_status(epd_pin_set);       //waiting for the electronic paper IC to release the idle signal

    epd_refresh(epd_pin_set);
     epd_write_cmd(epd_pin_set,0x02);  // Power OFF 
    epd_check_status(epd_pin_set);
}

void epd_clear_write(struct EPD_INFO_SET* epd_pin_set)
{
    unsigned int i;
  
    epd_write_cmd(epd_pin_set,0x13);
    for(i=0;i<38880;i++)       
    {   
        epd_write_data(epd_pin_set,0x00);  
    }

    epd_write_cmd(epd_pin_set,0x04); //POWER ON
    epd_check_status(epd_pin_set);       //waiting for the electronic paper IC to release the idle signal
    //Refresh
    epd_refresh(epd_pin_set);
    epd_write_cmd(epd_pin_set,0x02);  // Power OFF 
    epd_check_status(epd_pin_set);
}

// PAINT left_screen_paint;
// PAINT right_screen_paint;
void epd_display(struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData)
{
    unsigned int i;
  
    epd_write_cmd(epd_pin_set,0x13);
    for(i=0;i<38880;i++)       
    {   
        epd_write_data(epd_pin_set,picData[i]);
    }

    epd_write_cmd(epd_pin_set,0x04); //POWER ON
    epd_check_status(epd_pin_set);       //waiting for the electronic paper IC to release the idle signal
    //Refresh
    epd_refresh(epd_pin_set);

    epd_write_cmd(epd_pin_set,0x02);  // Power OFF 
    epd_check_status(epd_pin_set);
}
void epd_cache(struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData)
{
    unsigned int i;
  
    epd_write_cmd(epd_pin_set,0x13);
    for(i=0;i<38880;i++)       
    {   
        epd_write_data(epd_pin_set,picData[i]);
    }
}

void epd_display_partal(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
                         struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData)
{
    unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(epd_pin_set,0x91);   // partial in
    epd_check_status(epd_pin_set);
        
    epd_write_cmd(epd_pin_set,0x90);  
    epd_check_status(epd_pin_set);

    epd_write_data(epd_pin_set,Xstart_H);
    epd_write_data(epd_pin_set,Xstart_L);

    epd_write_data(epd_pin_set,Xend_H);
    epd_write_data(epd_pin_set,Xend_L);

    epd_write_data(epd_pin_set,Ystart_H);
    epd_write_data(epd_pin_set,Ystart_L);

    epd_write_data(epd_pin_set,Yend_H);
    epd_write_data(epd_pin_set,Yend_L);

    epd_write_data(epd_pin_set,0x01);

    epd_write_cmd(epd_pin_set,0x13); 
    epd_check_status(epd_pin_set);
 
    int i = 0;

    for(col=0; col<(Yend - Ystart); col++)						
    {
        for(row=0; row<((Xend - Xstart)/8); row++)						
        {
            epd_write_data(epd_pin_set,picData[i++]);
        }
    }

    epd_write_cmd(epd_pin_set,0x92); 
 
    epd_write_cmd(epd_pin_set,0x04);  // Power ON 
    epd_check_status(epd_pin_set);

    epd_refresh(epd_pin_set);

    epd_write_cmd(epd_pin_set,0x02);  // Power OFF 
    epd_check_status(epd_pin_set);
}

void epd_partial_cache(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,
                         struct EPD_INFO_SET* epd_pin_set,const unsigned char* picData)
{
    unsigned int row, col;

    uint8_t Xstart_H,Xstart_L,Ystart_H,Ystart_L,Xend_H,Xend_L,Yend_H,Yend_L;

    Xstart_H = ((Xstart)>>8) & 0xff;
    Xstart_L = (Xstart) & 0xff;

    Ystart_H = ((Ystart)>>8) & 0xff;
    Ystart_L = (Ystart) & 0xff;

    Xend_H = ((Xend-1)>>8) & 0xff;
    Xend_L = (Xend-1) & 0xff;

    Yend_H = ((Yend-1)>>8) & 0xff;
    Yend_L = (Yend-1) & 0xff;

    epd_write_cmd(epd_pin_set,0x91);   // partial in
    epd_check_status(epd_pin_set);
        
    epd_write_cmd(epd_pin_set,0x90);  
    epd_check_status(epd_pin_set);

    epd_write_data(epd_pin_set,Xstart_H);
    epd_write_data(epd_pin_set,Xstart_L);

    epd_write_data(epd_pin_set,Xend_H);
    epd_write_data(epd_pin_set,Xend_L);

    epd_write_data(epd_pin_set,Ystart_H);
    epd_write_data(epd_pin_set,Ystart_L);

    epd_write_data(epd_pin_set,Yend_H);
    epd_write_data(epd_pin_set,Yend_L);

    epd_write_data(epd_pin_set,0x01);

    epd_write_cmd(epd_pin_set,0x13); 
    epd_check_status(epd_pin_set);
 
    int i = 0;

    for(col=0; col<(Yend - Ystart); col++)						
    {
        for(row=0; row<((Xend - Xstart)/8); row++)						
        {
            epd_write_data(epd_pin_set,picData[i++]);
        }
    }
    epd_write_cmd(epd_pin_set,0x92); 
}

void epd_powerOn_refresh(struct EPD_INFO_SET* epd_pin_set)
{
    epd_write_cmd(epd_pin_set,0x04);  // Power ON 
    epd_check_status(epd_pin_set);

    epd_refresh(epd_pin_set);

    epd_write_cmd(epd_pin_set,0x02);  // Power OFF 
    epd_check_status(epd_pin_set);
}
#endif/*HAREWARE_SPI*/