# Seengreat 2.9 Inch E-Paper Display demo
import os
import sys
import spidev
import time
from gpiozero import LED,Button
import numpy as np

"""the following pin definiting use BCM"""

PIN_CS     = 8
PIN_DC     = 25
PIN_BUSY   = 24
PIN_RST    = 17
EPD_WIDTH  = 128
EPD_HEIGHT = 296
EPD_ARRAY  = EPD_WIDTH*EPD_HEIGHT//4
SOURCE_BITS=128
GATE_BITS  =296


EPD_2IN9G_BLACK  = 0x0
EPD_2IN9G_WHITE  = 0x1
EPD_2IN9G_YELLOW = 0x2
EPD_2IN9G_RED   =  0x3

class EPD_2Inch9():
    def __init__(self):

        # spi init
        # spi init
        self.bus = 0
        self.dev = 0
        self.spi_speed = 8000000
        self.spi = spidev.SpiDev()
        self.spi.open(self.bus, self.dev)
        self.spi.max_speed_hz = self.spi_speed
        self.spi.mode = 0b00
        #self.spi.no_cs = False
        # gpio init
        #self.cs = LED(PIN_CS)
        self.dc = LED(PIN_DC)
        self.rst = LED(PIN_RST)
        self.busy = Button(PIN_BUSY)
        self.w = EPD_WIDTH
        self.h = EPD_HEIGHT
        
    def write_cmd(self, cmd):
        """write command"""
        self.dc.off()#wpi.digitalWrite(PIN_DC,wpi.LOW)
        self.spi.writebytes([cmd])
        
    def write_data(self, value):
        """write data"""
        self.dc.on()#wpi.digitalWrite(PIN_DC,wpi.HIGH)
        self.spi.writebytes([value])
        
    def chkstatus(self):
        while 1:
             if self.busy.value==0:
                break

        
    def reset(self):
        """reset the epd"""
        self.rst.off()
        time.sleep(0.1)
        self.rst.on()
        time.sleep(0.1)
        
    def hw_init(self):
        """epd init..."""
        self.reset()
        print("ok")
        self.chkstatus()
        print("ok")
        self.write_cmd(0x4D)
        self.write_data(0x78)
        
        self.write_cmd(0x00) #Driver output control
        self.write_data(0x0F)
        self.write_data(0x29)


        self.write_cmd(0x01)  # Display update control
        self.write_data(0x07)
        self.write_data(0x00)
        
        self.write_cmd(0x03)  # Border Wave from
        self.write_data(0x10)
        self.write_data(0x54)
        self.write_data(0x44)
        
        self.write_cmd(0x06)  # data  entry  mode
        self.write_data(0x05)  # X-mode
        self.write_data(0x00)
        self.write_data(0x3F)
        self.write_data(0x0A)
        self.write_data(0x25)
        self.write_data(0x12)
        self.write_data(0x1A)

        self.write_cmd(0x50) 
        self.write_data(0x37)
        
        self.write_cmd(0x60)  # Display update control
        self.write_data(0x02)
        self.write_data(0x02)
        
        self.write_cmd(0x61) 
        self.write_data(SOURCE_BITS//256)
        self.write_data(SOURCE_BITS%256)
        self.write_data(GATE_BITS//256)
        self.write_data(GATE_BITS%256)  
        
        self.write_cmd(0xE7) 
        self.write_data(0x1C)
        
        self.write_cmd(0xE3) 
        self.write_data(0x22)
        
        self.write_cmd(0xB4) 
        self.write_data(0xD0)
        self.write_cmd(0xB5) 
        self.write_data(0X03)
        
        self.write_cmd(0xE9) 
        self.write_data(0x01)
        
        self.write_cmd(0x30) 
        self.write_data(0x08)
        
        self.write_cmd(0X04) 
        self.chkstatus()
        
        
    def update(self):
        self.write_cmd(0x12)
        self.write_data(0x00)
        self.chkstatus()

    def EPD_update(self):
        self.write_cmd(0x12)
        self.write_data(0x00)
        self.chkstatus()


    def sleep(self):
        self.write_cmd(0x02)
        self.chkstatus()
        time.sleep(0.1)
        self.write_cmd(0x07)
        self.write_data(0xA5)
                
    def Color_get(self,color):
        datas = 0
        if color == 0x00:
            datas = 0x01
        elif color == 0x01:
            datas = 0x02
        elif color == 0x02:
            datas = 0x03
        elif color == 0x03:
            datas = 0x00
        return datas

    def PIC_display(self,picData):
    
        self.write_cmd(0x10)
        for i in range(GATE_BITS):  # Source_BITS*Gate_BITS/4
            for j in range(SOURCE_BITS//4):
                temp1 = picData[i*SOURCE_BITS//4+ j]
            
                data_H1 = (self.Color_get(temp1 >> 6 & 0x03) << 6)
                data_H2 = (self.Color_get(temp1 >> 4 & 0x03) << 4)
                data_L1 = (self.Color_get(temp1 >> 2 & 0x03) << 2)
                data_L2 = self.Color_get(temp1 & 0x03)

                data = data_H1 | data_H2 | data_L1 | data_L2
                self.write_data(data)
  
        self.EPD_update()
        
    def GUI_display(self,picData):
        if EPD_WIDTH % 4 == 0:
            Width = EPD_WIDTH//4
        else:
            Width= (EPD_WIDTH // 4) + 1
        Height = EPD_HEIGHT;
    
        self.write_cmd(0x04)
        self.chkstatus()

        self.write_cmd(0x10)
        for i in range(Height):  # Source_BITS*Gate_BITS/4
            for j in range(Width):
                 self.write_data(picData[j + i * Width])
  
        self.EPD_update()
        
        
    def whitescreen_white(self):
        self.write_cmd(0x10) 
        for k in range(EPD_ARRAY):
            self.write_data(0x55)
        self.EPD_update()
        
        
    def whitescreen_black(self):
        self.write_cmd(0x10)
        for k in range(EPD_ARRAY):
            self.write_data(0x00)
        self.EPD_update()


    def whitescreen_red(self):
        self.write_cmd(0x10) 
        for k in range(EPD_ARRAY):
            self.write_data(0xff)
        self.EPD_update()


    def whitescreen_yellow(self):
        self.write_cmd(0x10) 
        for k in range(EPD_ARRAY):
            self.write_data(0xaa)
        self.EPD_update()
