diff --git a/python/PiFinder/displays.py b/python/PiFinder/displays.py new file mode 100644 index 00000000..cab8ce0c --- /dev/null +++ b/python/PiFinder/displays.py @@ -0,0 +1,111 @@ +from typing import Type +import functools +from collections import namedtuple + +import numpy as np +from PIL import Image + +from luma.core.interface.serial import spi +from luma.oled.device import ssd1351 +from luma.lcd.device import st7789 + + +ColorMask = namedtuple("ColorMask", ["mask", "mode"]) +RED_RGB: ColorMask = ColorMask(np.array([1, 0, 0]), "RGB") +RED_BGR: ColorMask = ColorMask(np.array([0, 0, 1]), "BGR") +GREY: ColorMask = ColorMask(np.array([1, 1, 1]), "RGB") + + +class Colors: + def __init__(self, color_mask: ColorMask, resolution: tuple[int, int]): + self.color_mask = color_mask[0] + self.mode = color_mask[1] + self.red_image = Image.new("RGB", (resolution[0], resolution[1]), self.get(255)) + + @functools.cache + def get(self, color_intensity): + arr = self.color_mask * color_intensity + result = tuple(arr) + return result + + +class DisplayBase: + resolution = (128, 128) + color_mask = RED_RGB + + def __init__(self): + self.colors = Colors(self.color_mask, self.resolution) + + def set_brightness(self, brightness: int) -> None: + return None + + +class DisplayPygame(DisplayBase): + resolution = (128, 128) + + def __init__(self): + from luma.emulator.device import pygame + + # init display (SPI hardware) + pygame = pygame( + width=128, + height=128, + rotate=0, + mode="RGB", + transform="scale2x", + scale=2, + frame_rate=60, + ) + self.device = pygame + + +class DisplaySSD1351(DisplayBase): + resolution = (128, 128) + + def __init__(self): + # init display (SPI hardware) + serial = spi(device=0, port=0) + device_serial = ssd1351(serial, rotate=0, bgr=True) + + device_serial.capabilities( + width=self.resolution[0], height=self.resolution[1], rotate=0, mode="RGB" + ) + self.device = device_serial + super().__init__() + + def set_brightness(self, level): + """ + Sets oled brightness + 0-255 + """ + self.device.contrast(level) + + +class DisplayST7789(DisplayBase): + resolution = (320, 240) + + def __init__(self): + # init display (SPI hardware) + serial = spi(device=0, port=0) + device_serial = st7789(serial, bgr=True) + + device_serial.capabilities( + width=self.resolution[0], height=self.resolution[1], rotate=0, mode="RGB" + ) + self.device = device_serial + super().__init__() + + +def get_display(hardware_platform: str) -> Type[DisplayBase]: + + if hardware_platform == "Fake": + return DisplayPygame() + + if hardware_platform == "Pi": + return DisplaySSD1351() + + if hardware_platform == "PFPro": + return DisplayST7789() + + else: + print("Hardware platform not recognized") diff --git a/python/PiFinder/image_util.py b/python/PiFinder/image_util.py index f761e140..5cf37bf6 100644 --- a/python/PiFinder/image_util.py +++ b/python/PiFinder/image_util.py @@ -11,45 +11,9 @@ import numpy as np import scipy.ndimage from enum import Enum -import functools -from collections import namedtuple import logging -ColorMask = namedtuple("ColorMask", ["mask", "mode"]) -RED_RGB: ColorMask = ColorMask(np.array([1, 0, 0]), "RGB") -RED_BGR: ColorMask = ColorMask(np.array([0, 0, 1]), "BGR") -GREY: ColorMask = ColorMask(np.array([1, 1, 1]), "RGB") - - -class Colors: - def __init__(self, color_mask: ColorMask): - self.color_mask = color_mask[0] - self.mode = color_mask[1] - self.red_image = Image.new("RGB", (128, 128), self.get(255)) - - @functools.cache - def get(self, color_intensity): - arr = self.color_mask * color_intensity - result = tuple(arr) - return result - - -class DeviceWrapper: - colors: Colors - - def __init__(self, device, color_mask: ColorMask): - self.device = device - self.colors = Colors(color_mask) - - def set_brightness(self, level): - """ - Sets oled brightness - 0-255 - """ - self.device.contrast(level) - - def make_red(in_image, colors): return ImageChops.multiply(in_image.convert("RGB"), colors.red_image) diff --git a/python/PiFinder/main.py b/python/PiFinder/main.py index e818f537..e33f6f99 100644 --- a/python/PiFinder/main.py +++ b/python/PiFinder/main.py @@ -22,6 +22,7 @@ import logging import argparse import pickle +from typing import Type from pathlib import Path from PIL import Image, ImageOps from multiprocessing import Process, Queue @@ -33,7 +34,6 @@ os.environ["OPENBLAS_NUM_THREADS"] = "1" os.environ["MKL_NUM_THREADS"] = "1" -from luma.core.interface.serial import spi from PiFinder import solver from PiFinder import integrator @@ -55,51 +55,17 @@ from PiFinder.state import SharedStateObj, UIState -from PiFinder.image_util import ( - subtract_background, - DeviceWrapper, - RED_RGB, - RED_BGR, - GREY, -) +from PiFinder.image_util import subtract_background + from PiFinder.calc_utils import sf_utils +from PiFinder.displays import DisplayBase, get_display hardware_platform = "Pi" -display_device: DeviceWrapper = DeviceWrapper(None, RED_RGB) +display_device: Type[DisplayBase] = DisplayBase() keypad_pwm = None -def init_display(): - global display_device - global hardware_platform - - if hardware_platform == "Fake": - from luma.emulator.device import pygame - - # init display (SPI hardware) - pygame = pygame( - width=128, - height=128, - rotate=0, - mode="RGB", - transform="scale2x", - scale=2, - frame_rate=60, - ) - display_device = DeviceWrapper(pygame, RED_RGB) - elif hardware_platform == "Pi": - from luma.oled.device import ssd1351 - - # init display (SPI hardware) - serial = spi(device=0, port=0) - device_serial = ssd1351(serial, rotate=0, bgr=True) - device_serial.capabilities(width=128, height=128, rotate=0, mode="RGB") - display_device = DeviceWrapper(device_serial, RED_RGB) - else: - print("Hardware platform not recognized") - - def init_keypad_pwm(): # TODO: Keypad pwm class that can be faked maybe? global keypad_pwm @@ -209,7 +175,8 @@ def main(script_name=None, show_fps=False, verbose=False): """ global display_device - init_display() + # display_device = get_display(hardware_platform) + display_device = get_display("PFPro") init_keypad_pwm() setup_dirs() diff --git a/python/PiFinder/splash.py b/python/PiFinder/splash.py index 1b1eb75d..416647ce 100644 --- a/python/PiFinder/splash.py +++ b/python/PiFinder/splash.py @@ -23,11 +23,13 @@ def do_nothing(): def init_display(): from luma.oled.device import ssd1351 + from luma.lcd.device import st7789 # init display (SPI hardware) serial = spi(device=0, port=0) - device_serial = ssd1351(serial, rotate=0, bgr=True) - device_serial.capabilities(width=128, height=128, rotate=0, mode="RGB") + # device_serial = ssd1351(serial, rotate=0, bgr=True) + device_serial = st7789(serial) + device_serial.capabilities(width=320, height=240, rotate=0, mode="RGB") device_serial.cleanup = do_nothing return device_serial @@ -57,7 +59,8 @@ def show_splash(): fill=(255, 0, 0), ) - display.display(welcome_image.convert(display.mode)) + display.display(welcome_image.resize((320, 240)).convert(display.mode)) + # display.display(welcome_image.convert(display.mode)) if __name__ == "__main__": diff --git a/python/PiFinder/ui/base.py b/python/PiFinder/ui/base.py index 816913ad..749c0838 100644 --- a/python/PiFinder/ui/base.py +++ b/python/PiFinder/ui/base.py @@ -7,11 +7,12 @@ import os import time import uuid +from typing import Type from PIL import Image, ImageDraw from PiFinder.ui.fonts import Fonts as fonts from PiFinder import utils -from PiFinder.image_util import DeviceWrapper +from PiFinder.displays import DisplayBase from PiFinder.config import Config @@ -28,7 +29,7 @@ class UIModule: def __init__( self, - device_wrapper: DeviceWrapper, + display: Type[DisplayBase], camera_image, shared_state, command_queues, @@ -39,13 +40,13 @@ def __init__( self.button_hints = self.__button_hints__ self.button_hints_timer = time.time() self.switch_to = None - self.display = device_wrapper.device - self.colors = device_wrapper.colors + self.display = display.device + self.colors = display.colors self.shared_state = shared_state self.ui_state = shared_state.ui_state() self.camera_image = camera_image self.command_queues = command_queues - self.screen = Image.new("RGB", (128, 128)) + self.screen = Image.new("RGB", display.resolution) self.draw = ImageDraw.Draw(self.screen) self.font_base = fonts.base self.font_bold = fonts.bold