# ascii5x7test3.py  2013-01-08
import RPi.GPIO as gpio
import time

print 'GPIO versiob=',gpio.VERSION

gpio.setmode(gpio.BCM)          # use broadcom gpio port numbering
                                # rather than board pin numbering
gpio.setup(23,gpio.OUT) # sda
gpio.setup(24,gpio.OUT) # scl
gpio.setup(25,gpio.OUT) # cs
gpio.output(23,0)       # serial data line initially low
gpio.output(24,0)       # serial clock line initially low
gpio.output(25,1)       # row-enable initially disabled

print 'bcm gpio23(sda), 24(scl), 25(cs) outputs set low, low, high'

# right bits -> top row bits
a5x7f=[[0x00, 0x00, 0x00, 0x00, 0x00], # (space)
[0x00, 0x00, 0x5F, 0x00, 0x00], # !
[0x00, 0x07, 0x00, 0x07, 0x00], # "
[0x14, 0x7F, 0x14, 0x7F, 0x14], # #
[0x24, 0x2A, 0x7F, 0x2A, 0x12], # $
[0x23, 0x13, 0x08, 0x64, 0x62], # %
[0x36, 0x49, 0x55, 0x22, 0x50], # &
[0x00, 0x05, 0x03, 0x00, 0x00], # '
[0x00, 0x1C, 0x22, 0x41, 0x00], # (
[0x00, 0x41, 0x22, 0x1C, 0x00], # )
[0x08, 0x2A, 0x1C, 0x2A, 0x08], # *
[0x08, 0x08, 0x3E, 0x08, 0x08], # +
[0x00, 0x50, 0x30, 0x00, 0x00], # ,
[0x08, 0x08, 0x08, 0x08, 0x08], # -
[0x00, 0x60, 0x60, 0x00, 0x00], # .
[0x20, 0x10, 0x08, 0x04, 0x02], # /
[0x3E, 0x51, 0x49, 0x45, 0x3E], # 0
[0x00, 0x42, 0x7F, 0x40, 0x00], # 1
[0x42, 0x61, 0x51, 0x49, 0x46], # 2
[0x21, 0x41, 0x45, 0x4B, 0x31], # 3
[0x18, 0x14, 0x12, 0x7F, 0x10], # 4
[0x27, 0x45, 0x45, 0x45, 0x39], # 5
[0x3C, 0x4A, 0x49, 0x49, 0x30], # 6
[0x01, 0x71, 0x09, 0x05, 0x03], # 7
[0x36, 0x49, 0x49, 0x49, 0x36], # 8
[0x06, 0x49, 0x49, 0x29, 0x1E], # 9
[0x00, 0x36, 0x36, 0x00, 0x00], # :
[0x00, 0x56, 0x36, 0x00, 0x00], # ;
[0x00, 0x08, 0x14, 0x22, 0x41], # <
[0x14, 0x14, 0x14, 0x14, 0x14], # =
[0x41, 0x22, 0x14, 0x08, 0x00], # >
[0x02, 0x01, 0x51, 0x09, 0x06], # ?
[0x32, 0x49, 0x79, 0x41, 0x3E], # @
[0x7E, 0x11, 0x11, 0x11, 0x7E], # A
[0x7F, 0x49, 0x49, 0x49, 0x36], # B
[0x3E, 0x41, 0x41, 0x41, 0x22], # C
[0x7F, 0x41, 0x41, 0x22, 0x1C], # D
[0x7F, 0x49, 0x49, 0x49, 0x41], # E
[0x7F, 0x09, 0x09, 0x01, 0x01], # F
[0x3E, 0x41, 0x41, 0x51, 0x32], # G
[0x7F, 0x08, 0x08, 0x08, 0x7F], # H
[0x00, 0x41, 0x7F, 0x41, 0x00], # I
[0x20, 0x40, 0x41, 0x3F, 0x01], # J
[0x7F, 0x08, 0x14, 0x22, 0x41], # K
[0x7F, 0x40, 0x40, 0x40, 0x40], # L
[0x7F, 0x02, 0x04, 0x02, 0x7F], # M
[0x7F, 0x04, 0x08, 0x10, 0x7F], # N
[0x3E, 0x41, 0x41, 0x41, 0x3E], # O
[0x7F, 0x09, 0x09, 0x09, 0x06], # P
[0x3E, 0x41, 0x51, 0x21, 0x5E], # Q
[0x7F, 0x09, 0x19, 0x29, 0x46], # R
[0x46, 0x49, 0x49, 0x49, 0x31], # S
[0x01, 0x01, 0x7F, 0x01, 0x01], # T
[0x3F, 0x40, 0x40, 0x40, 0x3F], # U
[0x1F, 0x20, 0x40, 0x20, 0x1F], # V
[0x7F, 0x20, 0x18, 0x20, 0x7F], # W
[0x63, 0x14, 0x08, 0x14, 0x63], # X
[0x03, 0x04, 0x78, 0x04, 0x03], # Y
[0x61, 0x51, 0x49, 0x45, 0x43], # Z
[0x00, 0x00, 0x7F, 0x41, 0x41], # [
[0x02, 0x04, 0x08, 0x10, 0x20], # "\"
[0x41, 0x41, 0x7F, 0x00, 0x00], # ]
[0x04, 0x02, 0x01, 0x02, 0x04], # ^
[0x40, 0x40, 0x40, 0x40, 0x40], # _
[0x00, 0x01, 0x02, 0x04, 0x00], # `
[0x20, 0x54, 0x54, 0x54, 0x78], # a
[0x7F, 0x48, 0x44, 0x44, 0x38], # b
[0x38, 0x44, 0x44, 0x44, 0x20], # c
[0x38, 0x44, 0x44, 0x48, 0x7F], # d
[0x38, 0x54, 0x54, 0x54, 0x18], # e
[0x08, 0x7E, 0x09, 0x01, 0x02], # f
[0x08, 0x14, 0x54, 0x54, 0x3C], # g
[0x7F, 0x08, 0x04, 0x04, 0x78], # h
[0x00, 0x44, 0x7D, 0x40, 0x00], # i
[0x20, 0x40, 0x44, 0x3D, 0x00], # j
[0x00, 0x7F, 0x10, 0x28, 0x44], # k
[0x00, 0x41, 0x7F, 0x40, 0x00], # l
[0x7C, 0x04, 0x18, 0x04, 0x78], # m
[0x7C, 0x08, 0x04, 0x04, 0x78], # n
[0x38, 0x44, 0x44, 0x44, 0x38], # o
[0x7C, 0x14, 0x14, 0x14, 0x08], # p
[0x08, 0x14, 0x14, 0x18, 0x7C], # q
[0x7C, 0x08, 0x04, 0x04, 0x08], # r
[0x48, 0x54, 0x54, 0x54, 0x20], # s
[0x04, 0x3F, 0x44, 0x40, 0x20], # t
[0x3C, 0x40, 0x40, 0x20, 0x7C], # u
[0x1C, 0x20, 0x40, 0x20, 0x1C], # v
[0x3C, 0x40, 0x30, 0x40, 0x3C], # w
[0x44, 0x28, 0x10, 0x28, 0x44], # x
[0x0C, 0x50, 0x50, 0x50, 0x3C], # y
[0x44, 0x64, 0x54, 0x4C, 0x44], # z
[0x00, 0x08, 0x36, 0x41, 0x00], # {
[0x00, 0x00, 0x7F, 0x00, 0x00], # |
[0x00, 0x41, 0x36, 0x08, 0x00], # }
[0x08, 0x04, 0x08, 0x10, 0x08], # ~
[0x08, 0x1C, 0x2A, 0x08, 0x08]] # <-


def rowdots(c):
    # from a char c
    # return a list of 7 row-lists of a 5 col bits
    # [[1st col bit list],[2nd col],...,[7th col]]
    oc=ord(c)
    if oc<0x20 or oc>0x7e:
        print "char out of range"
        return
    ci=oc-0x20
    bl=a5x7f[ci]
    rcb=[]
    for rn in range(7):
        rl=[]  # 0 or 1
        for cn in range(5):
            cb=bl[cn]
            bb=(cb >> rn) & 0x01
            rl.append(bb)
            #print '*' if bb else ' ',
        rcb.append(rl)
        #print
    return rcb
    

def srlist16(s):
    # s: string of 16 chars
    # return bigrows: 7-list (top=1, bot=7) of 83-list of (80 col bits + 3 row addr bits)
    # [80 col bits for col 1 + 3 row 1 bits],[col2 83 bits],...,[col7 83 bits]]
    # col bits are ordered msb -> lsb for each char, 16 char x 5 cols
    c16rc=[]
    for i in range(16):
        c16rc.append(rowdots(s[i]))
    bigrows=[] # 
    for r in range(7):
        bigrow=[]
        brn=[(r+1 >> rn) & 0x01 for rn in range(3)] #(top row=1, bot=7)
        brn.reverse() # msb -> lsb
        for cn in range(16):
            bigrow.extend(c16rc[cn][r]) # 80 bits of col data
        bigrow.extend(brn)              #  3 bits of row addr
        bigrows.append(bigrow)    
    return bigrows

def scl():
    # pulse serial clock high for about 10 uS on RPi
    gpio.output(24,0)
    gpio.output(24,1)
    gpio.output(24,0)

def rowenable():
    # turn on row leds
    gpio.output(25,0)

def rowdisable():
    # turn off row leds
    gpio.output(25,1)

def serbit(ibit):
    # clock 1 data bit out the sda port
    bit=1 if ibit else 0
    gpio.output(23,bit)
    scl()

def chrot16(rotidx):
    # return a 16 char subset of 95 ascii char set
    # from 0x20 to 0x7e
    # starting with index rotidx, whose range is 0..94
    idxlist=[(rotidx + i) % 95 for i in range(16)]
    chlist=[chr(i+0x20) for i in idxlist]
    return chlist


try:
    print 'scrolling characters, hit ctrl-C key to quit.
    while True:
        for i in range(95):
            chrs16=chrot16(i)
            srl=srlist16(chrs16) # 7 rows of 83 bits
            t0=time.time()
            while time.time()-t0<1.0: # refresh rows for 1 sec before scrolling
                for r in range(7):
                    rowdisable()
                    for b in range(83):
                        serbit(srl[r][b])
                    rowenable()
                    time.sleep(.001) # row enable dwell for 1 mS
except KeyboardInterrupt:
    pass

gpio.cleanup()
