#include "EPD_SPI.h"
#include <SPI.h>

// SPI
uint8_t SPI_SCK;
uint8_t SPI_MISO;
uint8_t SPI_MOSI;
uint8_t SPI_CS;
// EPD
uint8_t PIN_RES;
uint8_t PIN_DC;
uint8_t PIN_CS;
uint8_t PIN_BUSY;

void EPD_Pin_Init(uint8_t spi_sck, uint8_t spi_miso, uint8_t spi_mosi, uint8_t spi_cs,
    uint8_t epd_res, uint8_t epd_dc, uint8_t epd_cs, uint8_t epd_busy)
{
    PIN_RES = epd_res;
    PIN_DC = epd_dc;
    PIN_CS = epd_cs;
    PIN_BUSY = epd_busy;

    pinMode(PIN_BUSY, INPUT);  //BUSY
    pinMode(PIN_RES, OUTPUT); //RES 
    pinMode(PIN_DC, OUTPUT); //DC   
    pinMode(PIN_CS, OUTPUT); //CS

    SPI_SCK = spi_sck;
    SPI_MISO = spi_miso;
    SPI_MOSI = spi_mosi;
    SPI_CS = spi_cs;

    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 
    SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI, SPI_CS);
}

//SPI write byte
void SPI_Write(unsigned char value)
{				   			 
   SPI.transfer(value);
}

//SPI write command
void EPD_W21_WriteCMD(unsigned char command)
{
	EPD_W21_CS_0;
	EPD_W21_DC_0;  // D/C#   0:command  1:data  
	SPI_Write(command);
    //delay(500);
	EPD_W21_CS_1;
}
//SPI write data
void EPD_W21_WriteDATA(unsigned char datas)
{
	EPD_W21_CS_0;
	EPD_W21_DC_1;  // D/C#   0:command  1:data
	SPI_Write(datas);
    //delay(500);
	EPD_W21_CS_1;
}

// Save original SPI settings
SPIClass* originalSPI = &SPI;
uint8_t originalSdaPin = SPI_MISO;
uint8_t originalSclPin = SPI_SCK;
bool spiInitialized = false;
unsigned char EPD_W21_ReadDATA(void)
{
    unsigned char i, j = 0;
    // Save current hardware SPI configuration (only on first call)
    if (!spiInitialized) {
        spiInitialized = true;
    }
    originalSPI->end();    // Disable hardware SPI
    // Configure software SPI pins
    pinMode(SPI_MOSI, INPUT);     // SDA IN 
    pinMode(SPI_SCK, OUTPUT);    // SCL OUT 
    EPD_W21_CS_0;                   
    EPD_W21_DC_1;           // Data mode
    // Software SPI read
    for (i = 0; i < 8; i++) {
        digitalWrite(SPI_SCK, HIGH);  // SCL HIGH
        delayMicroseconds(2);    // More precise timing
        j = (j << 1);
        if (digitalRead(SPI_MOSI) == HIGH)
            j |= 0x01;
        delayMicroseconds(2);
        digitalWrite(SPI_SCK, LOW);   // SCL LOW
    } 
    EPD_W21_CS_1; 
    pinMode(SPI_MOSI, OUTPUT);// Restore MOSI to output mode 
    // Re-enable hardware SPI
    // Reinitialize with predefined default pins
    originalSPI->begin(originalSclPin, originalSdaPin, SPI_MOSI, SPI_CS);
    return j;
}