From e21f2a79cae0a79687061d30606599b930aa7480 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Sat, 1 Feb 2020 20:20:53 +0000 Subject: [PATCH] wasp: simulator: Add ST7789 simulation --- wasp/boards/simulator/display.py | 73 ++++++++++++++++++++++++++++++++ wasp/boards/simulator/machine.py | 22 ++++++++-- wasp/boards/simulator/watch.py | 14 ++++-- 3 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 wasp/boards/simulator/display.py diff --git a/wasp/boards/simulator/display.py b/wasp/boards/simulator/display.py new file mode 100644 index 0000000..dc303d9 --- /dev/null +++ b/wasp/boards/simulator/display.py @@ -0,0 +1,73 @@ +""" Simulated ST7789 display. """ + +import sys +import sdl2 +import sdl2.ext + +CASET = 0x2a +RASET = 0x2b +RAMWR = 0x2c + +class ST7789Sim(object): + def __init__(self, width=240, height=240): + sdl2.ext.init() + + self.width = width + self.height = height + + self.x = 0 + self.y = 0 + self.colclip = [0, width-1] + self.rowclip = [0, height-1] + self.cmd = 0 + + self.window = sdl2.ext.Window("ST7789", size=(width, height)) + self.window.show() + self.windowsurface = self.window.get_surface() + sdl2.ext.fill(self.windowsurface, (0, 0, 0)) + + def write(self, data): + if len(data) == 1: + # Assume if we get a byte at a time then it is command. + # This is a simplification do we don't have to track + # the D/C pin from within the simulator. + self.cmd = data[0] + + elif self.cmd == CASET: + self.colclip[0] = (data[0] << 8) + data[1] + self.colclip[1] = (data[2] << 8) + data[3] + self.x = self.colclip[0] + + elif self.cmd == RASET: + self.rowclip[0] = (data[0] << 8) + data[1] + self.rowclip[1] = (data[2] << 8) + data[3] + self.y = self.rowclip[0] + + elif self.cmd == RAMWR: + pixelview = sdl2.ext.PixelView(self.windowsurface) + + half = False + for d in data: + if not half: + rgb = d << 8 + half = True + continue + rgb |= d + half = False + + pixel = ((rgb & 0xf800) >> 8, + (rgb & 0x07e0) >> 3, + (rgb & 0x001f) << 3) + + pixelview[self.y][self.x] = pixel + + self.x += 1 + if self.x > self.rowclip[1]: + self.x = self.rowclip[0] + self.y += 1 + if self.y > self.colclip[1]: + self.y = self.colclip[0] + + # Forcibly release the surface to ensure it is unlocked + del pixelview + self.window.refresh() diff --git a/wasp/boards/simulator/machine.py b/wasp/boards/simulator/machine.py index 2c93770..3f8989f 100644 --- a/wasp/boards/simulator/machine.py +++ b/wasp/boards/simulator/machine.py @@ -1,3 +1,5 @@ +import display + class Tracer(object): def __init__(self, *args, **kwargs): print(f'{self.__class__.__name__}.__init__{args} {kwargs}') @@ -14,9 +16,10 @@ class Pin(object): IN = 'IN' OUT = 'OUT' - def __init__(self, id, direction, value=1): + def __init__(self, id, direction, value=1, quiet=False): self._id = id self._value = 0 + self._quiet = quiet def init(self, d, value): self.value(value) @@ -29,12 +32,16 @@ class Pin(object): def value(self, v=None): if v is None: + if not self._quiet: + print(f'{self._id}: read {self._value}') return self._value if v: - print(self._id + ": on") + if not self._quiet: + print(self._id + ": set on") self._value = False else: - print(self._id + ": off") + if not self._quiet: + print(self._id + ": set off") self._value = True def __call__(self, v=None): @@ -46,9 +53,16 @@ class PWM(Tracer): class SPI(object): def __init__(self, id): self._id = id + if id == 0: + self.sim = display.ST7789Sim() + else: + self.sim = None def init(self, baudrate=1000000, polarity=0, phase=0, bits=8, sck=None, mosi=None, miso=None): pass def write(self, buf): - print("Sending data: " + str(buf)) + if self.sim: + self.sim.write(buf) + else: + print("Sending data: " + str(buf)) diff --git a/wasp/boards/simulator/watch.py b/wasp/boards/simulator/watch.py index c6d695f..89faffe 100644 --- a/wasp/boards/simulator/watch.py +++ b/wasp/boards/simulator/watch.py @@ -9,6 +9,13 @@ from machine import SPI from drivers.st7789 import ST7789_SPI from drivers.vibrator import Vibrator +class Backlight(object): + def __init__(self, level=1): + self.set(level) + + def set(self, level): + print(f'BACKLIGHT: {level}') + class Display(ST7789_SPI): def __init__(self): spi = SPI(0) @@ -16,11 +23,12 @@ class Display(ST7789_SPI): spi.init(polarity=1, phase=1, baudrate=8000000) # Configure the display - cs = Pin("DISP_CS", Pin.OUT) - dc = Pin("DISP_DC", Pin.OUT) - rst = Pin("DISP_RST", Pin.OUT) + cs = Pin("DISP_CS", Pin.OUT, quiet=True) + dc = Pin("DISP_DC", Pin.OUT, quiet=True) + rst = Pin("DISP_RST", Pin.OUT, quiet=True) super().__init__(240, 240, spi, cs=cs, dc=dc, res=rst) display = Display() +backlight = Backlight() vibrator = Vibrator(Pin('MOTOR', Pin.OUT, value=0), active_low=True)