import RPi.GPIO as GPIO
import time
import datetime
#from threading import Thread
 
class LEDMatrix(object):
  delay = 0.000001
 
  GPIO.setmode(GPIO.BCM)
  GPIO.setwarnings(False)
  WIDTH=64
  HEIGHT=16 
  mask = 0xff
 
  digitals = bytearray([
    0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, # 0
    0x00, 0x18, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, # 1
    0x00, 0x3E, 0x63, 0x63, 0x63, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x63, 0x7F, 0x00, 0x00, 0x00, 0x00, # 2
    0x00, 0x3E, 0x63, 0x63, 0x06, 0x1C, 0x06, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, # 3
    0x00, 0x06, 0x0E, 0x1E, 0x36, 0x36, 0x66, 0x66, 0x7F, 0x06, 0x06, 0x1F, 0x00, 0x00, 0x00, 0x00, # 4
    0x00, 0x7F, 0x60, 0x60, 0x60, 0x7C, 0x76, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, # 5
    0x00, 0x1E, 0x36, 0x60, 0x60, 0x7C, 0x76, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, # 6
    0x00, 0x7F, 0x66, 0x66, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, # 7
    0x00, 0x3E, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, # 8
    0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x37, 0x1F, 0x03, 0x03, 0x36, 0x3C, 0x00, 0x00, 0x00, 0x00, # 9
    0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00  # A

  ])

# full ASCII character set (8x8) (760 bytes)
  font8x8_basic = bytearray([
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   # U+0020 (space)
     0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,   # U+0021 (!)
     0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   # U+0022 (")
     0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00,   # U+0023 (#)
     0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00,   # U+0024 ($)
     0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00,   # U+0025 (%)
     0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00,   # U+0026 (&)
     0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,   # U+0027 (')
     0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00,   # U+0028 (()
     0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00,   # U+0029 ())
     0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,   # U+002A (*)
     0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00,   # U+002B (+)
     0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06,   # U+002C (,)
     0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00,   # U+002D (-)
     0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00,   # U+002E (.)
     0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00,   # U+002F (/)
     0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00,   # U+0030 (0)
     0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00,   # U+0031 (1)
     0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00,   # U+0032 (2)
     0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00,   # U+0033 (3)
     0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00,   # U+0034 (4)
     0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00,   # U+0035 (5)
     0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00,   # U+0036 (6)
     0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00,   # U+0037 (7)
     0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00,   # U+0038 (8)
     0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00,   # U+0039 (9)
     0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00,   # U+003A (:)
     0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06,   # U+003B (//)
     0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00,   # U+003C (<)
     0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00,   # U+003D (=)
     0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00,   # U+003E (>)
     0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00,   # U+003F (?)
     0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00,   # U+0040 (@)
     0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00,   # U+0041 (A)
     0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00,   # U+0042 (B)
     0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00,   # U+0043 (C)
     0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00,   # U+0044 (D)
     0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00,   # U+0045 (E)
     0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00,   # U+0046 (F)
     0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00,   # U+0047 (G)
     0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00,   # U+0048 (H)
     0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   # U+0049 (I)
     0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00,   # U+004A (J)
     0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00,   # U+004B (K)
     0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00,   # U+004C (L)
     0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00,   # U+004D (M)
     0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00,   # U+004E (N)
     0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00,   # U+004F (O)
     0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00,   # U+0050 (P)
     0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00,   # U+0051 (Q)
     0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00,   # U+0052 (R)
     0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00,   # U+0053 (S)
     0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   # U+0054 (T)
     0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00,   # U+0055 (U)
     0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00,   # U+0056 (V)
     0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00,   # U+0057 (W)
     0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00,   # U+0058 (X)
     0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00,   # U+0059 (Y)
     0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00,   # U+005A (Z)
     0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00,   # U+005B ([)
     0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00,   # U+005C (\)
     0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00,   # U+005D (])
     0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,   # U+005E (^)
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,   # U+005F (_)
     0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,   # U+0060 (`)
     0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00,   # U+0061 (a)
     0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00,   # U+0062 (b)
     0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00,   # U+0063 (c)
     0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00,   # U+0064 (d)
     0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00,   # U+0065 (e)
     0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00,   # U+0066 (f)
     0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F,   # U+0067 (g)
     0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00,   # U+0068 (h)
     0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   # U+0069 (i)
     0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E,   # U+006A (j)
     0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00,   # U+006B (k)
     0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00,   # U+006C (l)
     0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00,   # U+006D (m)
     0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00,   # U+006E (n)
     0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00,   # U+006F (o)
     0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F,   # U+0070 (p)
     0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78,   # U+0071 (q)
     0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00,   # U+0072 (r)
     0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00,   # U+0073 (s)
     0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00,   # U+0074 (t)
     0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00,   # U+0075 (u)
     0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00,   # U+0076 (v)
     0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00,   # U+0077 (w)
     0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00,   # U+0078 (x)
     0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F,   # U+0079 (y)
     0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00,   # U+007A (z)
     0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00,   # U+007B ({)
     0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,   # U+007C (|)
     0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00,   # U+007D (})
     0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   # U+007E (~)
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   # U+007F (block)
  ])

  def __init__(self, red1_pin = 17, clock_pin = 3, a_pin = 7, b_pin = 8, c_pin = 9, d_pin = 10, latch_pin = 4, oe_pin = 2):
    super(LEDMatrix, self).__init__()
    self.row = 0
    self.red1_pin = red1_pin
    self.clock_pin = clock_pin
    self.a_pin = a_pin
    self.b_pin = b_pin
    self.c_pin = c_pin
    self.d_pin = d_pin
    self.latch_pin = latch_pin
    self.oe_pin = oe_pin
    GPIO.setup(self.red1_pin, GPIO.OUT)
    GPIO.setup(self.clock_pin, GPIO.OUT)
    GPIO.setup(self.a_pin, GPIO.OUT)
    GPIO.setup(self.b_pin, GPIO.OUT)
    GPIO.setup(self.c_pin, GPIO.OUT)
    GPIO.setup(self.d_pin, GPIO.OUT)
    GPIO.setup(self.latch_pin, GPIO.OUT)
    GPIO.setup(self.oe_pin, GPIO.OUT)

    self.displaybuf = bytearray([
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
      0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xE0, 0x07, 0x8F, 0xC7, 0xC7, 0xC7, 0xE0,
      0x00, 0x40, 0x0C, 0xCE, 0x6C, 0x6C, 0x6C, 0xE0, 0x00, 0xE0, 0x0C, 0x0C, 0x6C, 0x6C, 0x6C, 0x60,
      0x01, 0xF0, 0x07, 0x8C, 0x6F, 0xEF, 0xEC, 0x60, 0x23, 0xF8, 0x00, 0xCC, 0x6C, 0x0C, 0x0C, 0x60,
      0x33, 0xF8, 0x0C, 0xCE, 0x6C, 0x6C, 0x6C, 0xE0, 0x3B, 0xF8, 0x07, 0x8F, 0xC7, 0xC7, 0xC7, 0xE0,
      0x3B, 0xF8, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xF8, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00,
      0x0B, 0xF8, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ])

  def clear(self):
    for i in range (0,LEDMatrix.WIDTH * LEDMatrix.HEIGHT / 8):
	self.displaybuf[i]=0x00
 
  def bits_from_int(self,x):
    a_bit = x & 0x01
    b_bit = x & 0x02
    c_bit = x & 0x04
    d_bit = x & 0x08
    return (a_bit, b_bit, c_bit, d_bit)
 
  def set_row(self,row):
    a_bit, b_bit, c_bit, d_bit = self.bits_from_int(row)
    GPIO.output(self.a_pin, a_bit)
    GPIO.output(self.b_pin, b_bit)
    GPIO.output(self.c_pin, c_bit)
    GPIO.output(self.d_pin, d_bit)
 
  def scan(self):
    head = self.row * (LEDMatrix.WIDTH / 8)
    for line in range(0,LEDMatrix.HEIGHT / 16):
        index = head
        for byte in range (0, LEDMatrix.WIDTH / 8):
          pixels = self.displaybuf[index]
	  index += 1
	  pixels = pixels ^ LEDMatrix.mask
	  for bit in range (0,8):
	    GPIO.output(self.clock_pin,0)
            GPIO.output(self.red1_pin, pixels & (0x80 >> bit))
            GPIO.output(self.clock_pin,1)

    GPIO.output(self.oe_pin, 1)
    self.set_row(self.row)
    GPIO.output(self.latch_pin, 0)
    GPIO.output(self.latch_pin, 1)
    GPIO.output(self.latch_pin, 0)
    GPIO.output(self.oe_pin, 0)
    self.row = (self.row + 1) & 0x0F

  def moveLeft(self,rowstart,rowstop):
    nbPixels = 1
    for line in range(rowstart,rowstop):
      index = line * (LEDMatrix.WIDTH / 8 )
      for column in range (0, LEDMatrix.WIDTH / 8):
        if self.displaybuf[index] > 127: self.displaybuf[index] -= 128
        self.displaybuf[index] = self.displaybuf[index]<<nbPixels
        if (column != (LEDMatrix.WIDTH / 8) - 1 ):
  	  incomingchar = self.displaybuf[index+1] #byte
          for x in range (0, nbPixels): self.displaybuf[index] += ((incomingchar & (128>>x)) >> (7-x))<<(nbPixels-x-1)
        index += 1

  def drawDigital(self,x , y , n):
    #if (n >= 10 or (0 != (x %8))): return
    index = y * (WIDTH / 8) + x / 8
    idxvalue = n * 16 
    for i in range (0,16):
      self.displaybuf[index]=LEDMatrix.digitals[idxvalue]
      index += WIDTH / 8
      idxvalue += 1

  def drawCharacter(self, x , y , n):
    if (0 != (x % 8)): return    # x not a multiple of 8
    if ((n>9) and (n<32)): return # invalid character
    if ((n>=0) and (n<=9)): idxvalue=(n+16)
    else: idxvalue=(n-32) #go to the right code for this character
    idxvalue *= 8 
 
    index = y * (self.WIDTH / 8) + x / 8

    for i in range (0,8):
      self.displaybuf[index]=LEDMatrix.font8x8_basic[idxvalue]
      #reverse bit order
      self.displaybuf[index] = (self.displaybuf[index] & 0xF0) >> 4 | (self.displaybuf[index] & 0x0F) << 4
      self.displaybuf[index] = (self.displaybuf[index] & 0xCC) >> 2 | (self.displaybuf[index] & 0x33) << 2
      self.displaybuf[index] = (self.displaybuf[index] & 0xAA) >> 1 | (self.displaybuf[index] & 0x55) << 1
      index += self.WIDTH / 8
      idxvalue += 1
     
  def drawRect(self,x1, y1, x2, y2, pixel):
    for x in range(x1, x2):
        for y in range(y1, y2):
            self.drawPoint(y,x, pixel)
 
 
  def drawPoint(self, x , y , pixel):
    index = x / 8 + y * WIDTH / 8
    bit = x % 8 
    if (pixel):
      self.displaybuf[index] |= 0x80 >> bit
    else:
      self.displaybuf[index] &= ~(0x80 >> bit)


  def swipeColumn(self):
    for i in range (0,8):
      for j in range (0,120):
        self.scan()
      self.moveLeft(0,16)

#for 16x64
  def swipeLeft(self):
    for i in range (0,64):
      for j in range (0,120):
        self.scan()
      self.moveLeft(0,16)

#for 16x64
  def displayMessage(self,line1,line2 = ''):
  #should test length of messages
    lengthLine1 = len(line1)
    for char in range(lengthLine1):
      self.drawCharacter(char * 8, 0 , ord(line1[char]))
    if line2:
      for char in range(len(line2)):
        self.drawCharacter(char * 8, 8 , ord(line2[char]))

  def displayLongMessage(self,line1,rotate = 0):
    lengthLine1 = len(line1)
    for char in range(lengthLine1):
      if (char < 8):
        self.drawCharacter(char * 8, 4 , ord(line1[char]))
      else:
        self.swipeColumn()
        self.drawCharacter(56 , 4, ord(line1[char]))
    swipe = 0
    while rotate:
      self.swipeColumn()
      self.drawCharacter(56 , 4, ord(line1[swipe % lengthLine1]))
      swipe +=1
      if (swipe == 50): break
    self.swipeLeft()

