#!/usr/bin/python
# -*- encoding: utf-8 -*-

# ukazka rizeni displeje


# Pripojeni displeje 16x2 znaky:
#  konektor K20 .... expander .... displej  ....  vyznam signalu

#      11       ....   GPA0   ....   11     ....  D4
#      12       ....   GPA1   ....   12     ....  D5
#      13       ....   GPA2   ....   13     ....  D6
#      14       ....   GPA3   ....   14     ....  D7

#       4       ....   GPA4   ....    4     ....  RS (vyber registru : Prikazy / Data) 
#       6       ....   GPA5   ....    6     ....  E (potvrzeni dat) 
#      16       ....   GPA6   ....   16     ....  Katoda podsvetu (spinana pres tranzistor)

#       3       ....          ....    3     ....  Kontrast (trimrem nastavitelne napeti 0 az 5V)
#       1       ....          ....    1     ....  GND
#       5       ....          ....    5     ....  RW (GND)
#       2       ....          ....    2     ....  VDD (+5V)
#      15       ....          ....   15     ....  Anoda podsvetu (+5V)




import time
import smbus
import os

bus = smbus.SMBus(1)   # novejsi varianta RasPi (512MB)
#bus = smbus.SMBus(0)  # starsi varianta RasPi (256MB)

addr = 0x20 # adresa expanderu MCP23017 (podle nastavenych adresovacich vyvodu)



def main():

# ******** priklady pouziti podprogramu *********

  init()             # zakladni nastaveni systemu - smery portu na expanderu, reset a nastaveni displeje, rozsviceni podsvetu


#=================================================
  # tisk textu na urcenou pozici
  
  pozice(0,0)            # nastaveni pozice pro tisk (radka,sloupec); cislovano od 0,0 - LH roh
  slovo("abcdefghijklnopq")        # vytisknuti slova na prvni radku
  pozice(1,0)            # nastaveni pozice pro tisk
  slovo("0123456789ABCDEF")        # vytisknuti slova na druhou radku

  time.sleep(3)    # pauza 
  disclear()
  pozice(0,0)            # nastaveni pozice pro tisk (radka,sloupec); cislovano od 0,0 - LH roh
  slovo(" Test  podsvetu ")        # vytisknuti slova na prvni radku

  for i in range (5):
    podsvet(0)
    time.sleep(0.5)
    podsvet(1)
    time.sleep(0.5)

  pozice(0,0)
  slovo("  Konec  testu  ")        # vytisknuti napisu na prvni radku

  

# *****  konec ukazky ************  
#=================================================





#=================================================
# ***************   podprogramy *****************


# ovladani podsvetu, ktery je pripojeny na GPA6
def podsvet(pods):   # 1... rozsvitit; 0...zhasnout
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A

  if (pods == 1):
    novy = (porta | 0b01000000) # podsvetovy bit (GPA6) nastavit na 1
  else:
    novy = (porta & 0b10111111) # podsvetovy bit (GPA6) nastavit na 0 
  bus.write_byte_data(addr,0x12,novy) 
  

# prepinani prikazy / data
def regsel(rs): # 0...prikazy; 1...data
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A
  if (rs == 1):
    novy = (porta | 0b00010000) # pin prepinace rezimu (GPA4) nastavit na 1 (data) 
  else:
    novy = (porta & 0b11101111) # pin prepinace rezimu (GPA4) nastavit na 0 (prikazy)
  bus.write_byte_data(addr,0x12,novy) 


# zapis nastavenych dat do displeje kratkym nulovym pulsem
def strobe():   
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A
  novy = (porta & 0b11011111)                # strobe bit (GPA5) nastavit na 0
  bus.write_byte_data(addr,0x12,novy)
  time.sleep(0.0001) 
  bus.write_byte_data(addr,0x12,porta) # vratit strobe bit (GPA5) do 1
  time.sleep(0.0001) 

      
# odeslani pulbajtu do displeje (pb je v rozsahu 0 az 15)
def pulbajt(pb):   
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A
  signaly = (porta & 0b11110000)
  bus.write_byte_data(addr,0x12, pb + signaly) 
  strobe()


# odeslani bajtu rozlozeneho na 2 pulky do displeje
def bajt(b):  
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A
  signaly  = (porta & 0b11110000)
  hornipulbajt= ((b & 0b11110000)>>4)
  dolnipulbajt=  (b & 0b00001111)
  bus.write_byte_data(addr,0x12,hornipulbajt + signaly) 
  strobe()
  bus.write_byte_data(addr,0x12,dolnipulbajt + signaly) 
  strobe()



# zobrazeni jednoho ASCII znaku na aktualni pozici 
def znak(char):
  regsel(1)
  porta = bus.read_byte_data(addr,0x12) # precist aktualni stav na portu A
  signaly = (porta & 0b11110000)
  hornipulbajt= ((ord(char) & 0b11110000)>>4)
  dolnipulbajt= (ord(char) & 0b00001111)
  bus.write_byte_data(addr,0x12,hornipulbajt + signaly) 
  strobe()
  bus.write_byte_data(addr,0x12,dolnipulbajt + signaly) 
  strobe()
  
  

# zobrazeni textu na aktualni pozici 
#(POZOR, aby text neobsahoval znaky s ASCII kodem vyssim nez 127)
def slovo(text):   
  for i in range(len(text)):
    znak(text[i:i+1])
    



# nastaveni pozice na displeji
def pozice(rad,slo): # pocitano od pozice 0,0 = levy horni roh
  if rad == 0:       #horni radka
    adresa = 0x80 + slo
  if rad == 1:       #druha radka
    adresa = 0xC0 + slo

  regsel(0)
  bajt(adresa)


# smazani celeho displeje a nastaveni pozice na 0,0
def disclear():    
  regsel(0)
  bajt(0b00000001)
  time.sleep(0.003)
  bajt(0b00000010)
  time.sleep(0.003)



# zakladni nastaveni displeje (reset + nastaveni 4 dratoveho rezimu)
def init():
  
  # nastaveni expanderu - smery portu (IN/OUT)
  bus.write_byte_data(addr,0x00,0b00000000) # cely port A na OUT
  bus.write_byte_data(addr,0x12,0b00100000) # pin strobe zacina v "1"

  podsvet(1)


  # reset displeje - sekvence kodu podle datasheetu (nastaveni "ctyrdratoveho" datoveho vstupu)
  regsel(0)

  pulbajt(3)
  pulbajt(3)

  pulbajt(3)
  pulbajt(2)

  pulbajt(2)
  pulbajt(8)

  pulbajt(0)
  pulbajt(12)

  pulbajt(0)
  pulbajt(6)

  pulbajt(0)
  pulbajt(1)





if __name__ == '__main__':
  main()
