from machine import Pin, SPI, Timer
from time import sleep, sleep_us
from math import sin

class HUB08SPI(object):
  def __init__(self):
    self._spi = SPI(1, baudrate=10000000, polarity=0, phase=0) #MOSI=GPIO13, MISO=GPIO12, SCK=GPIO14
    self._buf = bytearray([
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,
0x3E,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x36,0xD8,0x00,0x00,0x01,0x80,0x00,0x00,0x36,0xD8,0x00,0x00,0x40,0x80,0x00,0x00,
0x36,0xD8,0x00,0x00,0x40,0x80,0x00,0x00,0x36,0xD9,0xF9,0xDC,0xF0,0xB0,0xF9,0xB0,
0x36,0xD8,0x84,0x88,0x40,0xC9,0x04,0xC8,0x36,0xD8,0x84,0x88,0x40,0x89,0x04,0x88,
0x36,0xD8,0x84,0x50,0x40,0x89,0x04,0x88,0x37,0xD8,0x84,0x50,0x48,0x89,0x04,0x88,
0x37,0xD0,0xF8,0x20,0x31,0xDC,0xF9,0xDC,0x13,0x98,0x80,0x20,0x00,0x00,0x00,0x00,
0x00,0x01,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
    self._font = bytearray([
0x00,0x08,0x7F,0xFC,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x04,0xFF,0xFE,0x01,0x00,
0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x10,0x10,0x20,0x0E,0xC0,0x04,
0x02,0x08,0x41,0x10,0x37,0xFC,0x10,0x80,0x01,0x08,0x03,0xFC,0xF2,0x08,0x13,0xF8,
0x12,0x08,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x2B,0xF8,0x44,0x06,0x03,0xFC,
0x02,0x44,0xFF,0x44,0x28,0x54,0x2A,0x54,0xFF,0x54,0xAA,0x54,0xAA,0xFC,0xAA,0x54,
0xC6,0x54,0x82,0x54,0xFE,0x54,0x82,0x54,0x82,0x94,0xFE,0x94,0x83,0x04,0x02,0x04,
0x22,0x20,0xFF,0xA0,0x22,0x20,0x3E,0x24,0x08,0xFE,0x7F,0x24,0x49,0x24,0x49,0x24,
0x7F,0x24,0x08,0x24,0x7F,0x24,0x08,0x24,0x3E,0x44,0x08,0x44,0xFF,0x94,0x01,0x08,
0x00,0x78,0x3F,0x80,0x11,0x10,0x09,0x20,0x7F,0xFE,0x42,0x02,0x82,0x04,0x7F,0xF8,
0x04,0x00,0x07,0xF0,0x0A,0x20,0x09,0x40,0x10,0x80,0x11,0x60,0x22,0x1C,0x0C,0x08,
0x04,0x80,0x0E,0xA0,0x78,0x90,0x08,0x90,0x08,0x84,0xFF,0xFE,0x08,0x80,0x08,0x90,
0x0A,0x90,0x0C,0x60,0x18,0x40,0x68,0xA0,0x09,0x20,0x0A,0x14,0x28,0x14,0x10,0x0C,
0x01,0x00,0x01,0x00,0x01,0x04,0x7F,0xFE,0x41,0x04,0x41,0x04,0x41,0x04,0x41,0x04,
0x7F,0xFC,0x41,0x04,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x04,0x40,0x04,0x48,0x08,0x58,0x08,0x60,0x18,0xC0,0x29,0x40,0x4A,0x44,0x08,0x44,
0x09,0x3C,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00])
    self.width = 64
    self.height = 16
    self._a = Pin(16, Pin.OUT)
    self._b = Pin(15, Pin.OUT)
    self._c = Pin(2, Pin.OUT)
    self._d = Pin(0, Pin.OUT)
    self._lat = Pin(5, Pin.OUT)
    self._oe = Pin(4, Pin.OUT, value=1)
    self._timer = Timer(-1)
    self._delay = 100
    self._line = 0

  def drawPoint(self, x, y, color):
    i = x // 8 + y * self.width // 8
    bit = x % 8
    if (color):
      self._buf[i] |= 0x80 >> bit
    else:
      self._buf[i] &= ~(0x80 >> bit)

  def drawRect(self, x1, y1, w, h, color):
    for x in range(x1, x1+w):
      for y in range(y1, y1+h):
        self.drawPoint(x, y, color)
  
  def clear(self):
    for i in range(len(self._buf)):
      self._buf[i] = 0
  
  def writeByte(self, x, y, data):
    offset = x & 7
    if offset:
      self.writeByte(x-offset,y,data>>offset)
      self.writeByte(x+8-offset,y,data<<(8-offset))
    else:
      self._buf[y*8+x//8] |= data
   
  def printChar(self, x, y, i):
    for a in range(16):
      self.writeByte(x,y+a, self._font[i*32+a*2])
      self.writeByte(x+8,y+a, self._font[i*32+a*2+1])
      
  def scan(self, foo=0):
    for line in range(16):
      self._lat.off()
      self._spi.write(self._buf[line*8:line*8+8])
      self._a.value(line & 1)
      self._b.value(line >> 1 & 1)
      self._c.value(line >> 2 & 1)
      self._d.value(line >> 3 & 1)
      self._lat.on()
      self._oe.off()
      sleep_us(256)
      self._oe.on()
    self._lat.off()
  
  def test_sinwave(self):
    self.clear()
    for x in range(64):
      y = round((sin(x/5.1)+1)*7.5)
      self.drawPoint(x, y, 1)
      
  def test_chinese(self):
    self.clear()
    for i in range(4):
      self.printChar(i*16, 0, i)
    sleep(1)
    self.clear()
    for i in range(4):
      self.printChar(i*16, 0, i+4)  
  
  def test_fill(self):
    for i in range(8):
      self.drawRect(i, i, 64-2*i, 16-2*i, (i+1)%2)
  
  def loop(self):
    self._timer.init(period=16, mode=Timer.PERIODIC, callback=self.scan)



