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

# ovladaci proogram pro displej "pg12864lrf-nra-h"
# (seriova komunikace)
# posledni uprava 11.5.2013


import time              # ruzne operace s casem (pauzy)
import RPi.GPIO as GPIO  # Ovladani GPIO vystupu v RasPi
import math              # vyuziva se jen v prikladech pri kresleni kruznic
import random            # vyuziva se v prikladu pro nahodne teckovani na displeji



###### P O Z O R ! #######
# tuto hodnotu si rucne upravte v rozsahu 0 az 15 tak, aby bylo zobrazeni na displeji dobre viditelne

defaultni_kontrast = 10

##########################


# tabulka pro prekodovani ceskych znaku z unicode na pozici v mensim fontu
cz={}
cz[345] = 253      # r s hackem
cz[237] = 161      # i s carkou
cz[353] = 231      # s s hackem
cz[382] = 167      # z s hackem
cz[357] = 156      # t s hackem
cz[269] = 159      # c s hackem
cz[253] = 236      # y s carkou
cz[367] = 133      # u s krouzkem
cz[328] = 229      # n s hackem
cz[250] = 163      # u s carkou
cz[283] = 216      # e s hackem
cz[271] = 212      # d s hackem
cz[225] = 160      # a s carkou
cz[233] = 130      # e s carkou
cz[243] = 162      # o s carkou

cz[344] = 252      # R s hackem
cz[205] = 214      # I s carkou
cz[352] = 230      # S s hackem
cz[381] = 166      # Z s hackem
cz[356] = 155      # T s hackem
cz[268] = 172      # C s hackem
cz[221] = 237      # Y s carkou
cz[366] = 222      # U s krouzkem
cz[327] = 213      # N s hackem
cz[218] = 233      # U s carkou
cz[282] = 183      # E s hackem
cz[270] = 210      # D s hackem
cz[193] = 181      # A s carkou
cz[201] = 144      # E s carkou
cz[211] = 224      # O s carkou

cz[228] = 158      # prehlasovane a
cz[235] = 159      # prehlasovane e
cz[239] = 160      # prehlasovane i
cz[246] = 161      # prehlasovane o
cz[252] = 162      # prehlasovane u
cz[196] = 163      # prehlasovane A
cz[214] = 164      # prehlasovane O
cz[220] = 165      # prehlasovane U

cz[176] = 166      # stupen
cz[177] = 241      # plus minus
cz[171] = 174      # dvojsipka vlevo
cz[166] = 173      # prerusene svislitko
cz[223] = 225      # beta



# preklad ceskych znaku z druheho (vetsiho) fontu
cz2={}
cz2[345] = 128      # r s hackem
cz2[237] = 129      # i s carkou
cz2[353] = 130      # s s hackem
cz2[382] = 131      # z s hackem
cz2[357] = 132      # t s hackem
cz2[269] = 133      # c s hackem
cz2[253] = 134      # y s carkou
cz2[367] = 135      # u s krouzkem
cz2[328] = 136      # n s hackem
cz2[250] = 137      # u s carkou
cz2[283] = 138      # e s hackem
cz2[271] = 139      # d s hackem
cz2[225] = 140      # a s carkou
cz2[233] = 141      # e s carkou
cz2[243] = 142      # o s carkou

cz2[344] = 143      # R s hackem
cz2[205] = 144      # I s carkou
cz2[352] = 145      # S s hackem
cz2[381] = 146      # Z s hackem
cz2[356] = 147      # T s hackem
cz2[268] = 148      # C s hackem
cz2[221] = 149      # Y s carkou
cz2[366] = 150      # U s krouzkem
cz2[327] = 151      # N s hackem
cz2[218] = 152      # U s carkou
cz2[282] = 153      # E s hackem
cz2[270] = 154      # D s hackem
cz2[193] = 155      # A s carkou
cz2[201] = 156      # E s carkou
cz2[211] = 157      # O s carkou

cz2[228] = 228      # prehlasovane a
cz2[235] = 235      # prehlasovane e
cz2[239] = 239      # prehlasovane i
cz2[246] = 246      # prehlasovane o
cz2[252] = 252      # prehlasovane u
cz2[196] = 196      # prehlasovane A
cz2[214] = 214      # prehlasovane O
cz2[220] = 220      # prehlasovane U

cz2[176] = 176      # stupen
cz2[177] = 177      # plus minus
cz2[171] = 171      # dvojsipka vlevo
cz2[166] = 166      # prerusene svislitko
cz2[223] = 223      # beta


GPIO.setwarnings(False)

# prirazeni GPIO pinu na signaly displeje
GPIO.setmode(GPIO.BOARD)   # cislovani podle GPIO pinu (1 az 26)
pin_res = 26  # reset na GPIO7 (pin 26) -> displej noha 2
pin_rs  = 15  # registry select na GPIO22 (pin 15) -> displej noha 4
pin_sda = 16  # seriova DATA na GPIO23 (pin 16) -> displej noha 18
pin_scl = 18  # hodiny na GPIO24 (pin 18) -> displej noha 17

# ostatni nohy displeje:
# 1 ... GND = (GPIO pin 6)
# 3 ... /CS = "0" (GPIO pin 6)
# 5 ... P/S = "0" (GPIO pin 6)
# 6 ... /WR = "1" (GPIO pin 1)
# 7 ... /RD = "0" (GPIO pin 6)
# 8 az 15 ... DATA - nezapojeno
# 16 ... +3,3V (GPIO pin 1)
# 19 ... podsvet A (GPIO 2 pres odpor 47R) - kvuli velkemu odberu podsvetu bylo k jeho
#          napajeni nutno vyuzit 5V. Proud byl omezen odporem. R = (5V - 3,3V) / 40mA = 42,5 Ohmu
# 20 ... podsvet K = GND (GPIO pin 6)

# nastaveni smeru GPIO
GPIO.setup(pin_res, GPIO.OUT) 
GPIO.setup(pin_rs , GPIO.OUT) 
GPIO.setup(pin_sda, GPIO.OUT) 
GPIO.setup(pin_scl, GPIO.OUT) 

# uvodni nastaveni vsech signalu na "0" (mimo resetu)
GPIO.output(pin_res, GPIO.HIGH)
GPIO.output(pin_scl, GPIO.LOW)
GPIO.output(pin_sda, GPIO.LOW)
GPIO.output(pin_rs , GPIO.LOW)

mapa={}
font={}
font2={}



# ==============================
# HLAVNI PROGRAM
# ==============================

def main():

  ginit()

  nacist_font("/home/pi/font.txt")   # nacteni obycejneho fontu
  nacist_font2("/home/pi/font2.txt") # nacteni tucneho fontu



#============================
# priklady pouziti:



  slovo ("Nastavení" , 3 , 0)
  slovo ("kontrastu", 3 , 12)
  slovo ("čekejte 15 sek.", 0 , 30)

  time.sleep(2)
  disclear()

  kontrast(0)  # nastaveni kontrastu na nejsvetlejsi hodnotu

  slovo ("Nastavení" , 3 , 0)
  slovo ("kontrastu", 3 , 12)
  for k in range(16):
    slovo ("Hodnota : " + str(k), 0 , 30)
    kontrast(k)
    time.sleep(0.8)  

  time.sleep(2)
  kontrast(defaultni_kontrast)
  disclear()

  slovo3 ("Kontrast", 4 , 10)
  slovo3 ("byl nastaven", 2 , 20)
  slovo3 ("na hodnotu: " + str(defaultni_kontrast), 1 , 30)

  time.sleep(2)

  #zaplneni displeje ruzne sirokymi svislymi pruhy
  disclear(0xCC)
  time.sleep(2)
  disclear(0xAA)
  time.sleep(2)
  disclear(0x11)
  time.sleep(2)
  disclear(0x00)  #smazani displeje


  # prime kresleni na displej (dve kruznice uprostred displeje)
  for kruh in range(0,6283,2):
    x1 = int(((math.sin(kruh/1000.0) * 32.0)) + 64)
    y1 = int(((math.cos(kruh/1000.0) * 32.0)) + 31)
    plot(x1,y1,1)
    x2 = int(((math.sin(kruh/1000.0) * 20.0)) + 64)
    y2 = int(((math.cos(kruh/1000.0) * 20.0)) + 31)
    plot(x2,y2,1)
  time. sleep(2)
    
  disclear()

  # nakresleni dvou horizontalnich car na horni a spodni mikroradce 10 pixelu od leveho i praveho okraje
  h_cara(0,10,117) 
  h_cara(63,10,117) 


  slovo ("To samé,", 5, 20)
  slovo ("ale rychleji.", 2,30)
  time. sleep(2)
  disclear()

  # to same kresleni, ale s vyuzitim pameti (rychlejsi)
  for kruh in range(0,6283,2):
    x1 = int(((math.sin(kruh/1000.0) * 32.0)) + 64)
    y1 = int(((math.cos(kruh/1000.0) * 32.0)) + 31)
    mem_plot(x1,y1,1)
    x2 = int(((math.sin(kruh/1000.0) * 20.0)) + 64)
    y2 = int(((math.cos(kruh/1000.0) * 20.0)) + 31)
    mem_plot(x2,y2,1)
  mem_dump()             # rychle preyspani obsahu pameti na displej
  time. sleep(2)



  slovo ("Okamžitá inverze", 0, 20)
  slovo ("celého  displeje", 0,28)
  time. sleep(2)
  inverze(True)  # rychla inverze
  time. sleep(2)
  inverze(False) # navrat na puvodni styl zobrazeni
  time. sleep(2)
  inverze(True)  # rychla inverze
  time. sleep(2)
  inverze(False) # navrat na puvodni styl zobrazeni
  time. sleep(2)
  disclear()


  # zobrazeni vsech znaku s kodem vetsim,nez 127 v 16 sloupcich a na 8 radkach pomoci funkce znak
  start = 128
  for i in range(start,256):
    znak(i,(i-start)%16 , int((i-start)/16)*8)

  time.sleep(3)
  disclear()

  # to same, jako predchozi smycka, ale tucnym fontem
  start = 128
  for i in range(start,256):
    znak3(i,(i-start)%16 , int((i-start)/16)*8)

  time.sleep(3)
  disclear()


  # zobrazeni napisu malym zhustenym fontem
  slovo2("Malý zhuštěný font" , 11,0)
  slovo2("zobrazený mimo rastr." , 3,8)
  mem_dump()  # po zobrazeni timto zpusobem musi nasledovat prikaz mem_dump() pro presypani pameti na displej

  # zobrazeni napisu malym fontem v rastru 8x8 bodu
  slovo("Nápis malým" , 2,16)
  slovo("fontem v rastru" , 0,24)
  slovo("8x8 bodů." , 4,32)

  # zobrazeni napisu velkym fontem
  slovo3("Příliš žluťoučký" , 0,40)
  slovo3("kůň úpěl" , 4,48)
  slovo3("ďábelské ódy." , 2,56)

  time.sleep(3)


  # vertikalni rolovani celeho displeje po mikroradkach
  vers={}
  vers[0] = " "
  vers[1] = "   Vertikální"
  vers[2] = "     rotace"
  vers[3] = " "
  vers[4] = "První řádka"
  vers[5] = "Druhá řádka"
  vers[6] = "Poslední řádka"
  vers[7] = "----------------"
  vers[8] = " "
  vers[9] = " "
  
  vert_rolovani(vers)
  time.sleep(2)
  # obnoveni souradnicoveho systemu do stavu, kdy LH roh ma souradnice [0,0]
  disclear()
  prikazy()
  sbajt(0x40)     # nastaveni StartLine na 0
  sbajt(0x50)     #   .. bity 5 a 4 ve StartLine taky na 0




  # nacteni cernobileho obrazku
  load_bmp12864("/home/pi/malina.bmp")
  time.sleep(3)


  # vyplneni displeje nahodnymi teckami, ktere invertuji puvodni obsah displeje
  for i in range(5000):
    x= int(random.random() * 128)
    y= int(random.random() * 64)
    plot(x,y,2)


  slovo("              " , 1,22)
  slovo(" KONEC UKÁZKY " , 1,30)
  slovo("              " , 1,38)


#    konec hlavniho programu
# ==============================





# ======= tady nasleduji vsechny podprogramy ======



# posle 8 bitu postupne na datovy drat. Pri kazdem bitu da impulz na hodinach
def sbajt(cislo):
  for i in range(8):                   # i = 0 az 7
    pozice = (128 >> i)                # pozice bitu se pri kazdem pruchodu smyckou posouva vpravo
    bit = ((cislo & pozice) >> (7-i))  # vypocet bitu "1" nebo "0"
    GPIO.output(pin_sda, bit)

    time.sleep(0.0000001)              # tiknuti hodinama do "1"
    GPIO.output(pin_scl, GPIO.HIGH)
    time.sleep(0.0000004)              # podle kat.listu musi pulz CLK-"H" trvat alespon 400ns
    GPIO.output(pin_scl, GPIO.LOW)     # a zpatky do "0"



# resetovaci impulz - resetuje se kratkou "0"
def reset():
  GPIO.output(pin_res, GPIO.LOW)
  time.sleep(0.000001)                 # podle kat.listu ma resetovaci "L" pulz trvat alespon mikrosekundu
  GPIO.output(pin_res, GPIO.HIGH)
  time.sleep(0.001)   # chvili pockat, nez se displej vzpamatuje z resetu




# nastaveni RS bitu na "prikazy"
def prikazy():
  GPIO.output(pin_rs, GPIO.HIGH)




# nastaveni RS bitu na "data"
def data():
  GPIO.output(pin_rs, GPIO.LOW)




#zakladni nastaveni displeje do grafickeho rezimu
def ginit():
  reset()

  prikazy()
  sbajt(0xB1) # power control register set: BIAS=1/9; Halt=0; PON=0; ACL=1 (inicializace)
  time.sleep(0.01)
  sbajt(0xB2) # power control register set: Power supply for the Graphic Display circuit = ON 
  sbajt(0x81) # Display Control Register Set : SHIFT=0; SEGMENT=0; ALLON=0; ON/OFF=0 (zhasnuti displeje)
  sbajt(0xDA) # Power ControlRegister Set(2) : (kontrast) napeti v rozsahu "0" az "F" nastaveno na "A"
  sbajt(0x93) # Display Control(2) Register Set: REV=0; NLIN=0; SWAP=1; REF=1
  sbajt(0xA3) # Increment ControlRegister Set: AIM=0; AY1=1; AX1=1
  sbajt(0x00) # X Address Register Set = 0 (AX3; AX2; AX1; AX0)
  sbajt(0x20) # Y Address Register Set = 0 (AY3; AY2; AY1; AY0)
  sbajt(0x30) # Y Address Register Set = 0 (AY6; AY5; AY4)
  disclear()




#vyplneni celeho displeje jednim kodem (smazani displeje)
def disclear(pattern = 0):
  prikazy()
  sbajt(0x00) # nastaveni uvodni polohy X = 0
  sbajt(0x20) # nastaveni uvodni polohy Y1 = 0
  sbajt(0x30) # nastaveni uvodni polohy Y2 = 0
  sbajt(0xA3) # automaticky posun aktualni pozice

  data()

  for i in range (1024): # zaplneni celeho displeje nejakym kodem 
    sbajt(pattern)
    gdisx = i % 16 
    gdisy = i / 16
    mapa[gdisx,gdisy] = pattern



# zmena kontrastu v urovnich 0 az 15 (0=nejsvetlejsi; 15=nejtmavsi)
def kontrast(con=8):
  if (con >= 0 and con < 16):
    prikazy()
    sbajt(0xD0 + con)




# okamzita inverze displeje
def inverze(inv = True):
  prikazy()
  if (inv == True):
    sbajt(0x93 + 8) # Display Control(2) Register Set: REV=1; NLIN=0; SWAP=1; REF=1
  else:
    sbajt(0x93)     # Display Control(2) Register Set: REV=0; NLIN=0; SWAP=1; REF=1




# zobrazeni(smazani/inverze) 1 bodu na souradnicich [x,y] v rozsahu [0 az 127, 0 az 63]
# styl: 0...smaz bod ; 1...zobraz bod, 2...invertuj bod
def plot(x,y,styl=1):
  adrx = x / 8 # poloha x-bajtu na displeji
  xbit = x % 8 # poloha bitu v x-bajtu

  puvodni_data = mapa[adrx,y] # zjisteni aktualniho stavu zobrazeni prislusneho bajtu
  if (styl == 0):    # smazani bodu
    novy_data = (~(0x80 >> xbit) & puvodni_data)
  if (styl == 1):    # zobrazeni bodu
    novy_data = ((0x80 >> xbit) | puvodni_data)
  if (styl == 2):    # inverze bodu
    novy_data = ((0x80 >> xbit) ^ puvodni_data)
  mapa[adrx,y] = novy_data

  prikazy()
  sbajt(0xA0) # v obou osach zrusit automaticke zvetsovani adresy

  # poloha X-bajtu na displeji
  sbajt(0x00 + adrx) # nastaveni X

  # poloha Y se do displeje zapisuje ve dvou castech
  ydolni = (y & 0x0f)         #  dolni 4 bity Y-polohy
  yhorni = ((y & 0x70) >> 4)  #  horni 3 bity Y polohy
  sbajt(0x20 + ydolni) # nastaveni polohy Y 
  sbajt(0x30 + yhorni) # nastaveni polohy Y

  data()
  sbajt(novy_data)




# stejna funkce jaklo plot(), akorat pracuje pouze s pameti 
def mem_plot(x,y,styl=1):   # rozsah souradnic [0,0] az [127,63]
  adrx = x / 8 # poloha x-bajtu na displeji (0 az 16)
  xbit = x % 8 # poloha bitu v x-bajtu

  puvodni_data = mapa[adrx,y] # zjisteni aktualniho stavu zobrazeni prislusneho bajtu
  
  if (styl == 0):    # smazani bodu
    novy_data = (~(0x80 >> xbit) & puvodni_data)
  if (styl == 1):    # zobrazeni bodu
    novy_data = ((0x80 >> xbit) | puvodni_data)
  if (styl == 2):    # inverze bodu
    novy_data = ((0x80 >> xbit) ^ puvodni_data)
  
  mapa[adrx,y] = novy_data
  




# rychle preneseni obsahu pameti (promenne mapa[]) do displeje:
def mem_dump():
  prikazy()
  sbajt(0x00) # nastaveni uvodni polohy X = 0
  sbajt(0x20) # nastaveni uvodni polohy Y1 = 0
  sbajt(0x30) # nastaveni uvodni polohy Y2 = 0
  sbajt(0xA3) # automaticky posun aktualni pozice

  data()
  for i in range (1024): # zaplneni celeho displeje obsahem promenne mapa[]
    gdisx = i % 16 
    gdisy = i / 16
    sbajt(mapa[gdisx,gdisy])
    


#=========================================================
# ======= operace s vetsim (tucnym) fontem =======
# tento font ma definovane znaky po osmi bajtech zhora dolu

# nacteni fontu ze souboru do seznamu "font2[]"
def nacist_font2(jmenosouboru):
  fontfile=file(jmenosouboru,"r")
  adresafontu=0
  for radka in fontfile:
    rozlozeno = radka.split(",")                   # vysosani jednotlivych bajtu z jedne radky ...
    for bajt in range(8):   # 8 bajtu na radce
      font2[adresafontu] = int(rozlozeno[bajt][-4:],0) # ... a ulozeni kazdeho toho bajtu do seznamu
      adresafontu = adresafontu + 1
  fontfile.close()



# zobrazeni jednoho znaku z vetsiho fontu
def znak3(kod,x,y):  # x=0 az 16 ,y= 0 az 63 (radka, na ktere je horni okraj znaku)
  kod = kod-32

  for adr in range(kod*8,(kod*8)+8):
    prikazy()
    sbajt(0x00 + x) # nastaveni polohy X

    ydolni = (y & 0x0f)         #  dolni 4 bity Y-polohy
    yhorni = ((y & 0x70) >> 4)  #  horni 3 bity Y polohy
    sbajt(0x20 + ydolni) # nastaveni polohy Y 
    sbajt(0x30 + yhorni) # nastaveni polohy Y

    data()
    sbajt(font2[adr])
    mapa[x,y]=font2[adr]
    y=y+1



#zobrazeni nekolika znaku za sebou vetsim (tucnym) fontem
def slovo3(text,x,y):  # x=0 az 15 ; y = 0 az 63 (horni okraj znaku)

  if (isinstance(text, unicode) == False):  # pokud text neni v unicode, tak ho preved
    text=  unicode(text, "utf-8")           # prevod textu z UTF-8 na unicode

  # cely text prochazet znak po znaku a tisknout
  for zn in range (len(text)):
    if (x < 16): # kontrola prekroceni sirky displeje
      if (ord(text[zn:zn + 1]) > 127):   # pokud jde o neASCII znak, provest prekodovani podle tabulky
        try:                    # pokud neni specialni kod nadefinovany v tabulce, ...
          znak3(cz2[ord(text[zn:zn + 1])], x, y)
        except:                 # ... skoncil by program chybou neexistujiciho indexu promenne cz2[].
          znak3(164, x, y)  # V tom pripade se nahradi nedefinovany znak znakem "kolecko s teckama"
      else:
        znak3(ord(text[zn:zn + 1]), x, y) # ASCII znaky tisknout normalne
      x=x+1




#==========================================================================
# ======= operace s mensim fontem (byl pouzity na displeji 128x128 bodu)=======
# tento font ma definovane znaky pomoci 5 bajtu zleva do prava

# nacteni fontu ze souboru do seznamu "font[]"
def nacist_font(jmenosouboru):
  fontfile=file(jmenosouboru,"r")
  adresafontu=0
  for radka in fontfile:
    rozlozeno = radka.split(",")                   # vysosani jednotlivych bajtu z jedne radky ...
    for bajt in range(5):
      font[adresafontu] = int(rozlozeno[bajt][-4:],0) # ... a ulozeni kazdeho toho bajtu do seznamu
      adresafontu = adresafontu + 1
  fontfile.close()

# bitove pootoceni znaku z mensiho fontu a zobrazeni na displeji
def znak(kod,x,y):  # x=0 az 16 ,y= 0 az 63 (radka, na ktere je horni okraj znaku)
  vert={}
  hbajt={}
  kod = kod-32
  mikro = 0

  for adr in range(kod*5,(kod*5)+5):
    vert[mikro] = font[adr]
    mikro=mikro+1
  for h in range(8):
    hbajt[h]=0
    for v in range(5):
      vbit = ((vert[4-v] & (2**h))>>h)
      hbajt[h] = hbajt[h] + (vbit << (v+3))  
  
    prikazy()
    sbajt(0x00 + x) # nastaveni polohy X

    ydolni = (y & 0x0f)         #  dolni 4 bity Y-polohy
    yhorni = ((y & 0x70) >> 4)  #  horni 3 bity Y polohy
    sbajt(0x20 + ydolni) # nastaveni polohy Y 
    sbajt(0x30 + yhorni) # nastaveni polohy Y

    data()
    sbajt(hbajt[h])
    mapa[x,y]=hbajt[h]
    y=y+1


#tisk nekolika znaku za sebou (mensi font)
def slovo(text,x,y):  # x=0 az 15; y (horni okraj znaku) = 0 az 63 

  if (isinstance(text, unicode) == False):  # pokud text neni v unicode, tak ho preved
    text=  unicode(text, "utf-8")           # prevod textu z UTF-8 na unicode

  # cely text prochazet znak po znaku a tisknout
  for zn in range (len(text)):
    if (x < 16):  # kontrola prekroceni sirky displeje
      if (ord(text[zn:zn + 1]) > 127):   # pokud jde o neASCII znak, provest prekodovani podle tabulky
        try:                    # pokud neni specialni kod nadefinovany v tabulce, ...
          znak(cz[ord(text[zn:zn + 1])], x, y)
        except:                 # ... skoncil by program chybou neexistujiciho indexu promenne cz[].
          znak(177, x, y)  # V tom pripade se nahradi nedefinovany znak znakem "sachovnice"

      else:
        znak(ord(text[zn:zn + 1]), x, y) # ASCII znaky tisknout normalne
      x=x+1



#------------
# tisk znaku z mensiho fontu bod po bodu (uspora prostoru, ale velmi pomale - proto se zapisuje pres pamet)
# souradnice LH rohu znaku v rozsahu [0,0] az [127,63] (napis na libovolne pozici - nezavisle na rastru)
def znak2(kod,x,y):  
  kod = kod-32
  mikrox=0
  for adr in range(kod*5,(kod*5)+5):
    if (x+mikrox < 128): # Znak se zobrazuje pouze v pripade, ze neprekroci okraj displeje
      for mikroy in range(8):
        if ((font[adr] & (2**mikroy)) == 0):  # zjisteni hodnoty kazdeho bitu v definici znaku
          mem_plot((x+mikrox),y+mikroy, 0)       # a podle toho se bod bud smaze ,
        else:
          mem_plot((x+mikrox),y+mikroy, 1)       # a nebo vykresli.
      mikrox = mikrox +1

  if (x+mikrox < 128):                     # kdyz je za znakem jeste nejake misto
    for mikroy in range(8):                # tak se vytvori jednopixelova mezera vysoka 8 bodu
      mem_plot((x+mikrox),y+mikroy, 0)
    mikrox = mikrox +1



#zobrazeni nekolika znaku za sebou (mensi font, usporny (zhusteny) rezim) 
# vzhledem k pomale rychlosti se napis uklada pouze do pameti (promenna mapa[])
# a na zaver je nutno tuto pamet presypat do displeje funkci "mem_dump()"
def slovo2(text,x,y):  # x=0 az 127; y (horni okraj znaku) = 0 az 63 

  if (isinstance(text, unicode) == False):  # pokud text neni v unicode, tak ho preved
    text=  unicode(text, "utf-8")           # prevod textu z UTF-8 na unicode

  # cely text prochazet znak po znaku a tisknout
  for zn in range (len(text)):
    if (ord(text[zn:zn + 1]) > 127):      # pokud jde o neASCII znak, provest prekodovani podle tabulky
      try:                                # pokud neni specialni kod nadefinovany v tabulce, ...
        znak2(cz[ord(text[zn:zn + 1])], x, y)
      except:                             # ... skoncil by program chybou neexistujiciho indexu promenne cz[].
        znak2(177, x, y)                  # V tom pripade se nahradi nedefinovany znak znakem sachovnice
    else:
      znak2(ord(text[zn:zn + 1]), x, y)   # ASCII znaky tisknout normalne
    x=x+6                                 # po kazdem znaku posunout pozici x o sirku znaku + jednu mezeru (5+1)





# vykresleni jednoduche horizontalni cary ve vysce "supery"
# pomoci parametru je mozne upravit parametry zacatku a konce cary
# parametr "styl" ma stejny vyznam, jako u funkce "plot" (nakreslit/smazat/invertovat)
def h_cara(supery, od=0 , do=127, styl=1):  
  for x in range(od, do+1):
    plot(x,supery,styl)



#rolovani s vyuzitim nastaveni "StartLine" v displeji
# rozhazi souradnicovy system, takze po pouziti je treba displej smazat znova nastavit StartLine na 0

def vert_rolovani(textove_pole):
  pocet_radek=len(textove_pole) # podle poctu indexu v poli se zjisti pocet nove vkladanych radek

  i=0 # pocitadlo mikroradek
  for roll in range ((pocet_radek+1)*8):

    horni_mradka = i         # aktualni cislo mikroradky na hornim okraji displeje
    dolni_mradka = 56 + i    # cislo mikroradky, na ktere se bude tisknout novy text (dole)

    
    prikazy()
    sbajt(0x40 + i%16)     # nastaveni StartLine se provadi ve dvou krocich (bity 3 az 0)
    sbajt(0x50 + int(i/16))     # bity 5 a 4
   
    # tim se horni mikroradka prenese na spodek displeje

    # nastaveni pozice pro mazani spodni mikroradky
    sbajt(0x00) # X = 0 (zacatek radky)
    sbajt(0x20 + horni_mradka%16)       # Y = poloha spodni mikroradky  (bity 3 az 0)
    sbajt(0x30 + int(horni_mradka/16))  # Y ...  (bity 5 a 4)

    data()
    for x in range (16):  # vymazani spodni mikroradky (prepsani 16 bajtu nulami)
      sbajt(0x00)


    if( roll%8 == 0 and roll != 0):  # po kazdem 8. posunu o mikroradku se dole vytiskne radka textu ze vstupu funkce
      slovo( textove_pole[int((roll-1)/8)] , 0 , dolni_mradka%64)
      time.sleep(0.1)   # protoze tisk textu chvili trva, musi byt nastavena trochu kratsi pauza, aby byl posun plynuly
    else:
      time.sleep(0.2)   # pauza mezi posuny o mikroradku 

    i = i + 1
    if (i > 63):  # kdyz dojde k prerotovani celeho displeje, tak se musi StartLine vynulovat
      i = 0       # a zaroven se vynuluje i pocitadlo mikroradek - promenna "i"
      prikazy()
      sbajt(0x40)     # nastaveni StartLine na 0
      sbajt(0x50)     #   .. bity 5 a 4 ve StartLine taky na 0
      



# nacteni dvoubarevneho BMP obrazku 128x64 bodu do promenne mapa[]
# POZOR: Bez jakychkoli testu na korektni format BMP souboru!
def load_bmp12864(jmeno_obrazku):
  soubor=open(jmeno_obrazku, "rb")  # nacteni obrazku do promenne data[]
  data = soubor.read()  
  soubor.close()                    # uzavreni souboru

  # podrobna specifikace hlavicky BMP souboru je tady:
  # http://www.root.cz/clanky/graficky-format-bmp-pouzivany-a-pritom-neoblibeny
  # zacatek obrazovych dat urcuji 4 bajty v souboru na pozicich 10 az 13 (desitkove) od zacatku souboru

  zacatekdat = ord(data[10]) + (ord(data[11]) * 256) + (ord(data[12]) * 65536) + (ord(data[13]) * 16777216)

  bajt=zacatekdat
  for mikroradka in range (63,-1,-1):  # cteni promenne data[] bajt po bajtu a postupne ukladani do pameti (mapa[])
    for sloupec in range (16):
      mapa[sloupec,mikroradka] = ~(ord(data[bajt]))  # BMP format ma invertovane bity, proto se bajt musi negovat
      bajt = bajt +1          # prejde na dalsi bajt z grafickych dat

  mem_dump()     # presypani obsahu promenne mapa[] na displej







if __name__ == '__main__':
  main()


