#include "2in9_epd.h"

/****************************
* PB12-----SPI2_NSS
* PB13-----SPI2_SCK
* PB15-----SPI2_MOSI
* PA8------DC
* PA11-----RST
* PA12-----BUSY
***************************/

void EPD_GPIO_Init(void)
{
		GPIO_InitTypeDef  GPIO_InitStructure;
		
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
										
		
		 //CS-->PB12   SCK-->PB13  SDO--->PB15 
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;		//Port configuration
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 			
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 		
		GPIO_Init(GPIOB, &GPIO_InitStructure);	  	
			
		 // D/C--->PA8	   RES-->PA11
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11;		//Port configuration
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 			
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 		
		GPIO_Init(GPIOA, &GPIO_InitStructure);	  				     		
		
		// BUSY--->PA12
		GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_12;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	//Pull up input
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);				//Initialize GPIO
}


void SPI_Write(unsigned char value)                                    
{                                                           
    unsigned char i;

    for(i=0; i<8; i++)   
    {
        EPD_W21_CLK = 0;
        if(value & 0x80)
        	EPD_W21_MOSI = 1;
        else
        	EPD_W21_MOSI = 0;		
        value = (value << 1); 
        EPD_W21_CLK = 1; 
    }
}

void EPD_W21_WriteCMD(unsigned char command)
{
  EPD_W21_CS = 0;                   
	EPD_W21_DC = 0;		// command write
	SPI_Write(command);
	EPD_W21_CS = 1;
}
void EPD_W21_WriteDATA(unsigned char data)
{
  EPD_W21_CS = 0;                   
	EPD_W21_DC = 1;		// data write
	SPI_Write(data);
	EPD_W21_CS = 1;
}

void delay_xms(unsigned int xms)
{
	unsigned int i;
	while(xms--)
	{
		i=12000;
		while(i--);
	}
}
///////////////////////////////////E-paper demo//////////////////////////////////////////////////////////
//Busy function
void Epaper_READBUSY(void)
{ 
  while(1)
  {  //=1 BUSY
     if(isEPD_W21_BUSY==1
			 ) break;
  }  
}
//Full screen refresh initialization
void EPD_HW_Init(void)
{
  EPD_W21_RST=0;  // Module reset   
  delay_xms(10);//At least 10ms delay 
  EPD_W21_RST=1;
  delay_xms(10); //At least 10ms delay 
  
  Epaper_READBUSY();   
	EPD_W21_WriteCMD(0x4D);
  EPD_W21_WriteDATA(0x78);

  EPD_W21_WriteCMD(0x00); //PSR
  EPD_W21_WriteDATA(0x0F);
  EPD_W21_WriteDATA(0x29);

  EPD_W21_WriteCMD(0x01); //PWRR
  EPD_W21_WriteDATA(0x07);
  EPD_W21_WriteDATA(0x00);
  
  EPD_W21_WriteCMD(0x03); //POFS
  EPD_W21_WriteDATA(0x10);
  EPD_W21_WriteDATA(0x54);
  EPD_W21_WriteDATA(0x44);
  
  EPD_W21_WriteCMD(0x06); //BTST_P
  EPD_W21_WriteDATA(0x05);
  EPD_W21_WriteDATA(0x00);
  EPD_W21_WriteDATA(0x3F);
  EPD_W21_WriteDATA(0x0A);
  EPD_W21_WriteDATA(0x25);
  EPD_W21_WriteDATA(0x12);
  EPD_W21_WriteDATA(0x1A); 

  EPD_W21_WriteCMD(0x50); //CDI
  EPD_W21_WriteDATA(0x37);
  
  EPD_W21_WriteCMD(0x60); //TCON
  EPD_W21_WriteDATA(0x02);
  EPD_W21_WriteDATA(0x02);
  
  EPD_W21_WriteCMD(0x61); //TRES
  EPD_W21_WriteDATA(SOURCE_BITS/256);   // SOURCE_BITS_H
  EPD_W21_WriteDATA(SOURCE_BITS%256);   // SOURCE_BITS_L
  EPD_W21_WriteDATA(GATE_BITS/256);     // GATE_BITS_H
  EPD_W21_WriteDATA(GATE_BITS%256);     // GATE_BITS_L  
  
  EPD_W21_WriteCMD(0xE7);
  EPD_W21_WriteDATA(0x1C);
  
  EPD_W21_WriteCMD(0xE3); 
  EPD_W21_WriteDATA(0x22);
  
  EPD_W21_WriteCMD(0xB4);
  EPD_W21_WriteDATA(0xD0);
  EPD_W21_WriteCMD(0xB5);
  EPD_W21_WriteDATA(0x03);
  
  EPD_W21_WriteCMD(0xE9);
  EPD_W21_WriteDATA(0x01); 

  EPD_W21_WriteCMD(0x30);
  EPD_W21_WriteDATA(0x08);  
  
  EPD_W21_WriteCMD(0x04);
  Epaper_READBUSY();
	
	
  
}


//////////////////////////////Display Update Function///////////////////////////////////////////////////////
//Full screen refresh update function
void EPD_Update(void)
{   
   EPD_W21_WriteCMD(0x12); 
  EPD_W21_WriteDATA(0x00);   
  Epaper_READBUSY();    
	
}

//Clear screen display
void EPD_WhiteScreen_White(void)
{
  unsigned int i;
  //Write Data
  EPD_W21_WriteCMD(0x10);      
  for(i=0;i<EPD_ARRAY;i++)       
  {
    EPD_W21_WriteDATA(0X55);  
  }
  EPD_Update();
}
//Display all black
void EPD_WhiteScreen_Black(void)
{
  unsigned int i;
  //Write Data
  EPD_W21_WriteCMD(0x10);      
  for(i=0;i<EPD_ARRAY;i++)       
  {
    EPD_W21_WriteDATA(0X00);  
  }
  EPD_Update();
}

//Display all red
void EPD_WhiteScreen_Red(void)
{
  unsigned int i;
  //Write Data
  EPD_W21_WriteCMD(0x10);      
  for(i=0;i<EPD_ARRAY;i++)       
  {
    EPD_W21_WriteDATA(0Xff);  
  }
  EPD_Update();
}

//Display all yellow
void EPD_WhiteScreen_Yellow(void)
{
  unsigned int i;
  //Write Data
  EPD_W21_WriteCMD(0x10);      
  for(i=0;i<EPD_ARRAY;i++)       
  {
    EPD_W21_WriteDATA(0Xaa);  
  }
  EPD_Update();
}

//Deep sleep function
void EPD_DeepSleep(void)
{   
  EPD_W21_WriteCMD(0x10); //Enter deep sleep
  EPD_W21_WriteDATA(0x01); 
  delay_xms(100);
}

unsigned char Color_get(unsigned char color)
{
  unsigned datas;
  switch(color)
  {
    case 0x00:
      datas=0x01;  
      break;    
    case 0x01:
      datas=0x02;
      break;
    case 0x02:
      datas=0x03;
      break;    
    case 0x03:
      datas=0x00;
      break;      
    default:
      break;      
  }
   return datas;
}

void PIC_display(const unsigned char* picData)
{
  unsigned int i,j;
  unsigned char temp1;
  unsigned char data_H1,data_H2,data_L1,data_L2,data;
   
  EPD_W21_WriteCMD(0x10);        
  for(i=0;i<GATE_BITS;i++)  //SOURCE_BITS*GATE_BITS/4
  { 
    for(j=0;j<SOURCE_BITS/4;j++)
    {   
      temp1=picData[i*SOURCE_BITS/4+j]; 

      data_H1=Color_get(temp1>>6&0x03)<<6;      
      data_H2=Color_get(temp1>>4&0x03)<<4;
      data_L1=Color_get(temp1>>2&0x03)<<2;
      data_L2=Color_get(temp1&0x03);
      
      data=data_H1|data_H2|data_L1|data_L2;
      EPD_W21_WriteDATA(data);
    }
  } 
   //Refresh
    EPD_Update();  
}



void GUI_display(const unsigned char* picData)
{
  unsigned int Width, Height,i,j; 
    Width = (EPD_WIDTH % 4 == 0)? (EPD_WIDTH / 4 ): (EPD_WIDTH / 4 + 1);
    Height = EPD_HEIGHT;
    
    EPD_W21_WriteCMD(0x04);
    Epaper_READBUSY();

    EPD_W21_WriteCMD(0x10);
    for ( j = 0; j < Height; j++) {
        for ( i = 0; i < Width; i++) {
            EPD_W21_WriteDATA(picData[i + j * Width]);
        }
    }

    EPD_Update();

}