"""

1. Sample Python code.
For driving ST7036 as part of DISPLAY VISIONS ELECTRONIC ASSEMBLY DOG-series 3.3V
This code includes the (minimum needed) SPI serial driver bus protocol for master transmit operation.

The software enables a demonstration startpoint and can be further used at own risk.
The software is provided "as is", without warranty of any kind, express or implied,
including but not limited to the warranties of merchantability,
fitness for a particular purpose and noninfringement.
In no event shall the authors or copyright holders be liable for any claim,
damages or other liability, whether in an action of contract, tort or otherwise,
arising from, out of or in connection with the software or the use or other dealings in the software.  

*** THERE IS NO FREE SUPPORT ON THIS PIECE OF CODE ***
Contact for a possible co-operation / feedback : tomesenmark@gmail.com


2. General background info ST7036 Register setup copy from datasheet.
During read or write operation, two 8-bit registers are used.
One is Data Register (DR) for target display text,
the other is Instruction Register(IR) for initialization/configuration.

RS R/W Operation table :

 |RS |R/W|
 --------------------------------------------------------------------------
 | L | L | Instruction Write operation (MPU writes Instruction code into IR)
 | L | H | Read Busy Flag(DB7) and address counter (DB0 ~ DB6)
 | H | L | Data Write operation (MPU writes data into DR)
 | H | H | Data Read operation (MPU reads data from DR)


3. Validation setup and Hardware application scheme.

The following configuration is tested:
- EA DOGM162W-A (2 row display)
- EA LED55x31-G (light green backlight)
- Raspberry Pi PICO (RP2040) control unit

For this DOG application only IR and DR Write operations are used.
This means R/W can be put at logical 0 (grounded in application) and only RS pin is hardwired to PICO port.

For this DOG application only 1 device is connected to SPI system bus.
This means that the NOT(Chip Select Bit) pin can be grounded.


4. Main test program is included in this sample code.
The result indicates that program time / character @ Pico application can be ~ 0.5 ms 

"""

# libraries
import time
from machine import Pin

# SPI definitions
                 
ST7036_CLK=Pin(2)                                        # PICO pin #4: CLK                  
ST7036_Tx=Pin(3)                                         # PICO pin #5: SDI data transmit
ST7036_rs=Pin(8)                                         # PICO pin #11: select between DR and IR

# constants
n=0                                                      # time.sleep multiplier

class DOG1602:
    
    def __init__(self,col,row):
        self._col = col
        self._row = row
    
    # generic function to write a byte
    def ST7036_write_byte(self,data):                    # provide decimal value of byte
      
        test_pattern_MSB = 128                           # decimal/integer representation of b'0x80' 
        for local in range (0,8):                        # probe data bit by bit and drive Tx bit
            test_result = bool(data & test_pattern_MSB)  # Python"s bitwise operator (only) operates on integers
            if test_result == True :                                  # generate Tx bit
                ST7036_Tx.on()                                        # generate Tx HIGH
            else:
                ST7036_Tx.off()                                       # generate Tx LOW
                # time.sleep(n*0.001)                                 # optional delay                     
            ST7036_CLK.off()                                          # generate clock LOW
            #time.sleep(n*0.001)                                      # optional delay 
            ST7036_CLK.on()                                           # generate clock HIGH
            #time.sleep(n*0.001)                                      # optional delay 
            test_pattern_MSB >>= 1                                    # bit wise shifting of the test_pattern

    # write a byte into the Control register (needs RS at logical 0)
    def ST7036_write_command_byte(self, data):
        ST7036_rs.off()
        time.sleep(n*0.001)                                           # optional delay 
        DOG1602.ST7036_write_byte(self,data)
        return
 
 # write a byte into the Data register (needs RS at logical 1)
    def ST7036_write_data_byte(self,data):
        ST7036_rs.on()
        time.sleep(n*0.001)                                           # optional delay 
        DOG1602.ST7036_write_byte(self,data)
 
 # initialisation
    def ST7036_init(self):
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,57)      # 0X39 Function Set; 8 bit datawords, 2 rows, instruction table 1
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,20)      # 0X14 Bias Set; BS 1/5; 2 line display
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,120)     # 0X78 Set contrast C3, C2, C1
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,85)      # 0X55 Power Cintrol; booster on, contrast C5, set C4 
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,109)     # 0X6D Follower control; set voltage follower and gain
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,15)      # 0X0F Display on/off; display on, cursor on, cursor blink
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,1)       # 0X01 Clear Display; delete display, cursor home 
        time.sleep(n*0.001)
        DOG1602.ST7036_write_command_byte(self,6)       # 0X06 Entry mode set; Cursor Auto-Increment ...
                         ## ... Warning : Need auto increment for fastest clearline function implementation ##
        # print('init done')                            # debug only
        return      

    # put the cursor at position [x,y] = [column,row]
    # [0,0] is left upper position; [15,2] is lower right position
    def ST7036_goto_xy(self,x,y):                  # integer inputs
        DOG1602.ST7036_write_command_byte(self,(128 + 64 * y + x))
        # print('goto done')                            # debug only
        return 

    # write a single character into the Data register 
    def ST7036_put_char(self,char):
        bytes_val=char.encode('utf-8')
        int_val = int.from_bytes(bytes_val, "big")                    # byteorder is big where MSB is at start
        DOG1602.ST7036_write_data_byte(self,int_val)

    # write a string of characters into the Data register
    def ST7036_put_string(self,string):
        for local in range (0, len(string)):                          # iterate through string
            bytes_val=string[local].encode('utf-8')
            int_val= int.from_bytes(bytes_val, "big")                 # byteorder is big where MSB is at start
            DOG1602.ST7036_write_data_byte(self,int_val)

    # write a string of decimals into the Data register
    def ST7036_put_value(self,value):                                      
        number = str(value)
        DOG1602.ST7036_put_string(self,number)

    def ST7036_clearline(self,row):                                   # line 0 [upper] and line 1 [lower] are defined
        DOG1602.ST7036_goto_xy(self,0,row)
        for position in range (0,16):               # may be this is not Pythonic but works (fastest),
                                                    # only need 16 write commands, at every write iteration...      
            DOG1602.ST7036_write_data_byte(self,0)  # ...the cursor automatically increments 1 position forward                   

    def ST7036_clear(self):
        DOG1602.ST7036_clearline(self,0)
        DOG1602.ST7036_clearline(self,1)


# main program (demonstration function example)
def demo():
    
    import DOG_Mark_lib 
    
    # SPI definitions for driver
    ST7036_CLK=machine.Pin(2,Pin.OUT)                                 # PICO pin #4 : CLK
    ST7036_Tx=machine.Pin(3,Pin.OUT)                                  # PICO pin #5 : SDI data transmit
    ST7036_rs=machine.Pin(8,Pin.OUT)                                  # PICO pin #11: I2C bus for 10DOF IMU uses pin 6 and pin 7 

    # constants for display driver
    n=0                                                               # time.sleep multiplier
    lcd = DOG_Mark_lib.DOG1602(16,2)

    lcd.ST7036_init()
    lcd.ST7036_clear()
    time.sleep(1)

    #---------------------
    start = time.ticks_us()

    lcd.ST7036_goto_xy(0,0)
    lcd.ST7036_put_string("Does it work...?")
    time.sleep(2)

    lcd.ST7036_clearline(0)
    lcd.ST7036_goto_xy(7,0)
    lcd.ST7036_put_value(42)
    time.sleep(1)

    lcd.ST7036_goto_xy(7,1)
    lcd.ST7036_put_value(4)
    time.sleep(1)
    lcd.ST7036_put_char("2")
    time.sleep(1)

    lcd.ST7036_goto_xy(11,1)
    lcd.ST7036_put_string("yes !")
    time.sleep(1)
    lcd.ST7036_clearline(0)

    end = time.ticks_us()
    #--------------------

    usecs = time.ticks_diff(end,start)
    usecs_corr = (usecs-6000000)/57000                                # (3*16)+2+1+1+5=57 characters - corrected for sleeptime
    print("program time/character ~ %.2f"%(usecs_corr),"milli seconds") 
     
if __name__ == '__main__':
    demo()

