#include "Ap_29demo.h"
#include "7inch5_epd.h"
#include <SPI.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "Arduino.h"
#include "epd_gui.h"
/***************************************************************************************
 * Project  :
 * Experimental Platform :Arduino Mega 2560 + 7.5inch E-Paper Display
 * Hardware Connection :Arduino Mega 2560-> 7.5inch E-Paper
 * Pin wiring definion
 * VCC---->5V
 * GND---->GND
 * RST---->D9
 * BUSY--->D10
 * D/C---->D8
 * MOSI--->D51
 * CLK---->D52
 * CS----->D53
 * Author      : Andy Li
 * Web Site    :www.seengreat.com
***************************************************************************************/
void Canvas_Display_With_Red(void);
#define CANVAS_WIDTH    200
#define CANVAS_HEIGHT   120
#define CANVAS_X        120  
#define CANVAS_Y        110
static uint8_t canvasBuffer[CANVAS_WIDTH*CANVAS_HEIGHT/8];

void setup() {
    Serial.begin(115200);
   Serial.print("Init gpio for arduino\r\n");
   pinMode(BUSY_Pin, INPUT); 
   pinMode(RES_Pin, OUTPUT);  
   pinMode(DC_Pin, OUTPUT);    
   pinMode(CS_Pin, OUTPUT);    
   //SPI
   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 
   SPI.begin ();  
}
//Tips//
/*
1.Flickering is normal when EPD is performing a full screen update to clear ghosting from the previous image so to ensure better clarity and legibility for the new image.
2.There will be no flicker when EPD performs a partial refresh.
3.Please make sue that EPD enters sleep mode when refresh is completed and always leave the sleep mode command. Otherwise, this may result in a reduced lifespan of EPD.
4.Please refrain from inserting EPD to the FPC socket or unplugging it when the MCU is being powered to prevent potential damage.)
5.Re-initialization is required for every full screen update.
6.When porting the program, set the BUSY pin to input mode and other pins to output mode.
*/
void loop() {
      unsigned char i;
      EPD_Init(); //Full screen refresh initialization.
      EPD_WhiteScreen_White(); //Clear screen function.    
      EPD_DeepSleep(); //Enter the sleep mode and please do not delete it, otherwise it will reduce the lifespan of the screen.
      delay(2000); //Delay for 2s. 
     
      EPD_Init(); //Full screen refresh initialization.
      PIC_display(gImage_BW,gImage_RW);
      EPD_DeepSleep(); //Enter the sleep mode and please do not delete it, otherwise it will reduce the lifespan of the screen.
      delay(2000); //Delay for 2s
      delay(2000); //Delay for 2s. . 

      EPD_Init(); //Full screen refresh initialization.
      EPD_WhiteScreen_White(); //Clear screen function.    
      EPD_DeepSleep(); //Enter the sleep mode and please do not delete it, otherwise it will reduce the lifespan of the screen.

				/*Initialize the canvas*/
      Image_Init(canvasBuffer, CANVAS_WIDTH, CANVAS_HEIGHT, ROTATE_0, EPD_7IN5G_WHITE);
      
      Gui_Draw_Rectangle(5, 10, 45, 60,EPD_7IN5G_BLACK,FULL,PIXEL_1X1);
      Gui_Draw_Rectangle(55, 10, 95, 60,EPD_7IN5G_BLACK,EMPTY,PIXEL_1X1);
      Gui_Draw_Circle(125,35,20,EPD_7IN5G_BLACK,FULL,PIXEL_1X1);
      Gui_Draw_Circle(175,35,20,EPD_7IN5G_BLACK,EMPTY,PIXEL_1X1);
      Gui_Draw_Line(0, 90, 200, 90, EPD_7IN5G_BLACK, PIXEL_1X1, SOLID);
      Gui_Draw_Line(0, 100, 200, 100, EPD_7IN5G_BLACK, PIXEL_1X1, SOLID);
      
      Gui_Draw_Point(5, 110, EPD_7IN5G_BLACK, PIXEL_2X2, DOT_STYLE_DFT);
      Gui_Draw_Point(15, 110, EPD_7IN5G_BLACK, PIXEL_3X3, DOT_STYLE_DFT);
      Gui_Draw_Point(27, 110, EPD_7IN5G_BLACK, PIXEL_4X4, DOT_STYLE_DFT);	
      Gui_Draw_Str(40, 105, "SEENGREAT", &Font12, EPD_7IN5G_WHITE, EPD_7IN5G_BLACK);

      /*partial refresh*/
      EPD_Init_Part();
      EPD_Dis_Part(CANVAS_X,CANVAS_Y, canvasBuffer, CANVAS_HEIGHT,CANVAS_WIDTH);
      Canvas_Display_With_Red();
      EPD_DeepSleep(); //Enter the sleep mode and please do not delete it, otherwise it will reduce the lifespan of the screen.
      delay(2000); //Delay for 2s.
      delay(2000); //Delay for 2s.

      EPD_Init(); //Electronic paper initialization.  
      EPD_WhiteScreen_White();
      EPD_Init_Part(); //Pa refresh initialization.
      for(i=0;i<6;i++)
      {
         EPD_Dis_Part_Time(240,180,Num[1],Num[0],gImage_numdot,Num[0],Num[i],5,104,48); //x,y,DATA-A~E,Resolution 48*104                 
      }       
      EPD_DeepSleep();  //Enter the sleep mode and please do not delete it, otherwise it will reduce the lifespan of the screen.
      delay(2000); //Delay for 2s.

      EPD_Init(); //Full screen refresh initialization.
      EPD_WhiteScreen_White(); //Clear screen function.
      delay(1000); //Delay for 2s.
      while(1);  // The program stops here   
}
//////////////////////////////////END//////////////////////////////////////////////////
/*Add the desired red range that you want to achieve here*/
static uint8_t GetPixelColor_Display(uint16_t x, uint16_t y) {
    if(x >= 5 && x <= 45 && y >= 10 && y <= 60) {
        return EPD_7IN5G_RED;
    }
		if(x >= 55 && x <= 95 && y >= 10 && y <= 60) {
        return EPD_7IN5G_RED;
    }
    return EPD_7IN5G_BLACK;
}

void Canvas_Display_With_Red(void) {
    uint32_t i, j, k;
    uint16_t canvasX, canvasY;
    uint8_t byte, oldData, newData;
    
    EPD_Init();
    
    // Transfer old data (0x10) - Black/White data
    EPD_W21_WriteCMD(0x10);
    for(i = 0; i < EPD_HEIGHT; i++) {
        for(j = 0; j < EPD_WIDTH / 8; j++) {
            if(i >= CANVAS_Y && i < CANVAS_Y + CANVAS_HEIGHT && 
               j >= CANVAS_X / 8 && j < (CANVAS_X + CANVAS_WIDTH) / 8) {
                // Inside canvas area
               canvasX = j - CANVAS_X / 8;
               canvasY = i - CANVAS_Y;
               byte = canvasBuffer[canvasY * (CANVAS_WIDTH / 8) + canvasX];
                
                // For black/white data, we set all pixels to white (0xFF) except those that are black in canvas
                // Red pixels will also be set to white here (they'll be handled in the red data)
                oldData = ~byte; // Invert because 0 is white, 1 is black in the display
                EPD_W21_WriteDATA(oldData);
            } else {
                // Outside canvas area - white
                EPD_W21_WriteDATA(0xFF); // All white
            }
        }
    }
    
    // Transfer new data (0x13) - Red data
    EPD_W21_WriteCMD(0x13);
    for(i = 0; i < EPD_HEIGHT; i++) {
        for(j = 0; j < EPD_WIDTH / 8; j++) {
            if(i >= CANVAS_Y && i < CANVAS_Y + CANVAS_HEIGHT && 
               j >= CANVAS_X / 8 && j < (CANVAS_X + CANVAS_WIDTH) / 8) {
                // Inside canvas area
                canvasX = j - CANVAS_X / 8;
                canvasY = i - CANVAS_Y;
                byte = canvasBuffer[canvasY * (CANVAS_WIDTH / 8) + canvasX];
                
                // For red data, we need to check which pixels should be red
                // Here we use the GetPixelColor1 function to determine if a pixel should be red
                newData = 0;
                for(k = 0; k < 8; k++) {
                    uint16_t px = j*8 + k;
                    uint16_t py = i;
                    if(byte & (1 << (7 - k))) { // If pixel is set in canvas
                        if(GetPixelColor_Display(px - CANVAS_X+1, py - CANVAS_Y+1) == EPD_7IN5G_RED) {
                            newData |= (1 << (7 - k)); // Set red pixel
                        }
                    }
                }
                EPD_W21_WriteDATA(newData);
            } else {
                // Outside canvas area - no red
                EPD_W21_WriteDATA(0x00); // No red
            }
        }
    }
    
    EPD_Update();
}