mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2026-04-28 09:53:06 -07:00
Add PiSugar Whisplay to supported displays.
Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com>
This commit is contained in:
@@ -26,6 +26,9 @@ class Display(View):
|
||||
)
|
||||
self._render_thread_instance.start()
|
||||
|
||||
def is_whisplay(self):
|
||||
return self._implementation.name == 'whisplay'
|
||||
|
||||
def is_lcdhat(self):
|
||||
return self._implementation.name == 'lcdhat'
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ def display_for(config):
|
||||
from pwnagotchi.ui.hw.inky import Inky
|
||||
return Inky(config)
|
||||
|
||||
elif config['ui']['display']['type'] == 'whisplay':
|
||||
from pwnagotchi.ui.hw.whisplay import Whisplay
|
||||
return Whisplay(config)
|
||||
|
||||
elif config['ui']['display']['type'] == 'inkyv2':
|
||||
from pwnagotchi.ui.hw.inkyv2 import InkyV2
|
||||
return InkyV2(config)
|
||||
|
||||
429
pwnagotchi/ui/hw/libs/whisplay/whisplaydriver.py
Normal file
429
pwnagotchi/ui/hw/libs/whisplay/whisplaydriver.py
Normal file
@@ -0,0 +1,429 @@
|
||||
import RPi.GPIO as GPIO
|
||||
import spidev
|
||||
import time
|
||||
|
||||
|
||||
class WhisPlayBoard:
|
||||
# LCD 参数
|
||||
LCD_WIDTH = 240
|
||||
LCD_HEIGHT = 280
|
||||
CornerHeight = 20 # 圆角高度占的像素
|
||||
DC_PIN = 13
|
||||
RST_PIN = 7
|
||||
LED_PIN = 15
|
||||
|
||||
# RGB LED 引脚
|
||||
RED_PIN = 22
|
||||
GREEN_PIN = 18
|
||||
BLUE_PIN = 16
|
||||
|
||||
# 按键引脚
|
||||
BUTTON_PIN = 11
|
||||
|
||||
def __init__(self):
|
||||
self._gpio_initialized = False
|
||||
|
||||
try:
|
||||
GPIO.setmode(GPIO.BOARD)
|
||||
self._gpio_initialized = True
|
||||
except RuntimeError as e:
|
||||
# GPIO mode already set, continue
|
||||
print(f"GPIO.setmode warning: {e}")
|
||||
self._gpio_initialized = True
|
||||
except Exception as e:
|
||||
print(f"GPIO initialization failed: {e}. Display will run in limited mode.")
|
||||
self._gpio_initialized = False
|
||||
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
# 初始化 LCD 引脚
|
||||
if self._gpio_initialized:
|
||||
try:
|
||||
GPIO.setup([self.DC_PIN, self.RST_PIN, self.LED_PIN], GPIO.OUT)
|
||||
except Exception as e:
|
||||
# Pins might already be set up or GPIO access denied
|
||||
print(f"Warning: LCD GPIO setup failed: {e}")
|
||||
self._gpio_initialized = False
|
||||
|
||||
if self._gpio_initialized:
|
||||
try:
|
||||
GPIO.output(self.LED_PIN, GPIO.LOW) # 使能背光
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not set LED output: {e}")
|
||||
|
||||
# 初始化 RGB LED 引脚
|
||||
if self._gpio_initialized:
|
||||
try:
|
||||
GPIO.setup([self.RED_PIN, self.GREEN_PIN, self.BLUE_PIN], GPIO.OUT)
|
||||
self.red_pwm = GPIO.PWM(self.RED_PIN, 100)
|
||||
self.green_pwm = GPIO.PWM(self.GREEN_PIN, 100)
|
||||
self.blue_pwm = GPIO.PWM(self.BLUE_PIN, 100)
|
||||
self._current_r = 0
|
||||
self._current_g = 0
|
||||
self._current_b = 0
|
||||
self.red_pwm.start(0)
|
||||
self.green_pwm.start(0)
|
||||
self.blue_pwm.start(0)
|
||||
except Exception as e:
|
||||
print(f"Warning: RGB LED setup failed: {e}")
|
||||
self.red_pwm = None
|
||||
self.green_pwm = None
|
||||
self.blue_pwm = None
|
||||
else:
|
||||
self.red_pwm = None
|
||||
self.green_pwm = None
|
||||
self.blue_pwm = None
|
||||
|
||||
self.backlight_pwm = None
|
||||
|
||||
# 初始化按键
|
||||
if self._gpio_initialized:
|
||||
try:
|
||||
GPIO.setup(self.BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||
self.button_press_callback = None
|
||||
self.button_release_callback = None
|
||||
GPIO.add_event_detect(
|
||||
self.BUTTON_PIN, GPIO.BOTH, callback=self._button_event, bouncetime=50
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Warning: Button setup failed: {e}")
|
||||
self.button_press_callback = None
|
||||
self.button_release_callback = None
|
||||
else:
|
||||
self.button_press_callback = None
|
||||
self.button_release_callback = None
|
||||
|
||||
# 初始化 SPI
|
||||
self.spi = spidev.SpiDev()
|
||||
self.spi.open(0, 0)
|
||||
self.spi.max_speed_hz = 100_000_000
|
||||
self.spi.mode = 0b00
|
||||
|
||||
self.previous_frame = None
|
||||
# 检测硬件版本并设置背光模式
|
||||
self._detect_hardware_version()
|
||||
self._detect_wm8960()
|
||||
|
||||
# Initialize offset attributes for compatibility
|
||||
self._offset_left = 0
|
||||
self._offset_top = 0
|
||||
|
||||
# Only initialize display if GPIO was successfully set up
|
||||
if self._gpio_initialized:
|
||||
try:
|
||||
self.set_backlight(0)
|
||||
self._reset_lcd()
|
||||
self._init_display()
|
||||
self.fill_screen(0)
|
||||
except Exception as e:
|
||||
print(f"Warning: Display initialization failed: {e}")
|
||||
else:
|
||||
print("Warning: GPIO not available, skipping display initialization. SPI will be attempted directly.")
|
||||
|
||||
def _detect_hardware_version(self):
|
||||
"""
|
||||
检测树莓派硬件版本,并根据版本设置背光模式
|
||||
"""
|
||||
try:
|
||||
with open("/proc/cpuinfo", "r") as f:
|
||||
lines = f.readlines()
|
||||
model_name = None
|
||||
for line in lines:
|
||||
if line.startswith("Model"):
|
||||
model_name = line.strip().split(":")[1].strip()
|
||||
break
|
||||
if model_name:
|
||||
if "Zero" in model_name and "2" not in model_name:
|
||||
# 如果是 Zero 或 Zero W
|
||||
self.backlight_mode = False # 使用简单开关模式
|
||||
else:
|
||||
# 其他型号(如 Zero 2 W, 3B, 4B 等)
|
||||
self.backlight_mode = True # 使用 PWM 模式
|
||||
print(
|
||||
f"Detected hardware: {model_name}, Backlight mode: {'PWM' if self.backlight_mode else 'Simple Switch'}")
|
||||
else:
|
||||
print("Model name not found in /proc/cpuinfo")
|
||||
self.backlight_mode = True # 默认使用 PWM 模式
|
||||
except Exception as e:
|
||||
print(f"Error detecting hardware version: {e}")
|
||||
self.backlight_mode = True # 默认使用 PWM 模式
|
||||
|
||||
def _detect_wm8960(self):
|
||||
"""
|
||||
检测是否存在名字包含 wm8960 的声卡
|
||||
"""
|
||||
try:
|
||||
with open("/proc/asound/cards", "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if "wm8960" in line.lower():
|
||||
print("wm8960 sound card detected.")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error detecting wm8960 sound card: {e}")
|
||||
return False
|
||||
|
||||
print("wm8960 sound card driver is installed. Please refer to the following page for installation instructions.")
|
||||
print("https://docs.pisugar.com/")
|
||||
return False
|
||||
|
||||
# ========== 背光控制 ==========
|
||||
def set_backlight(self, brightness):
|
||||
if not self._gpio_initialized:
|
||||
return
|
||||
|
||||
if self.backlight_mode: # 如果是 PWM 模式
|
||||
if self.backlight_pwm is None:
|
||||
try:
|
||||
self.backlight_pwm = GPIO.PWM(self.LED_PIN, 1000)
|
||||
self.backlight_pwm.start(100)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not create backlight PWM: {e}")
|
||||
return
|
||||
if 0 <= brightness <= 100:
|
||||
try:
|
||||
duty_cycle = 100 - brightness
|
||||
self.backlight_pwm.ChangeDutyCycle(duty_cycle)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not set backlight: {e}")
|
||||
else: # 如果是简单开关模式
|
||||
try:
|
||||
if brightness == 0:
|
||||
GPIO.output(self.LED_PIN, GPIO.HIGH) # 关闭背光
|
||||
else:
|
||||
GPIO.output(self.LED_PIN, GPIO.LOW) # 打开背光
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not control backlight: {e}")
|
||||
|
||||
def set_backlight_mode(self, mode):
|
||||
"""
|
||||
设置背光模式
|
||||
:param mode: True 使用 PWM 调节亮度,False 使用简单开关控制
|
||||
"""
|
||||
if mode == self.backlight_mode:
|
||||
return # 模式未改变,无需操作
|
||||
|
||||
if mode: # 切换到 PWM 模式
|
||||
self.backlight_pwm = GPIO.PWM(self.LED_PIN, 1000)
|
||||
self.backlight_pwm.start(100)
|
||||
else: # 切换到简单开关模式
|
||||
if self.backlight_pwm is not None:
|
||||
self.backlight_pwm.stop()
|
||||
self.backlight_pwm = None
|
||||
GPIO.output(self.LED_PIN, GPIO.HIGH) # 确保背光打开
|
||||
self.backlight_mode = mode
|
||||
|
||||
def _reset_lcd(self):
|
||||
if not self._gpio_initialized:
|
||||
print("Warning: Cannot reset LCD - GPIO not initialized")
|
||||
return
|
||||
try:
|
||||
GPIO.output(self.RST_PIN, GPIO.HIGH)
|
||||
time.sleep(0.1)
|
||||
GPIO.output(self.RST_PIN, GPIO.LOW)
|
||||
time.sleep(0.1)
|
||||
GPIO.output(self.RST_PIN, GPIO.HIGH)
|
||||
time.sleep(0.12)
|
||||
except Exception as e:
|
||||
print(f"Warning: LCD reset failed: {e}")
|
||||
|
||||
def _init_display(self):
|
||||
self._send_command(0x11)
|
||||
time.sleep(0.12)
|
||||
USE_HORIZONTAL = 1
|
||||
direction = {0: 0x00, 1: 0xC0, 2: 0x70,
|
||||
3: 0xA0}.get(USE_HORIZONTAL, 0x00)
|
||||
self._send_command(0x36, direction)
|
||||
self._send_command(0x3A, 0x05)
|
||||
self._send_command(0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33)
|
||||
self._send_command(0xB7, 0x35)
|
||||
self._send_command(0xBB, 0x32)
|
||||
self._send_command(0xC2, 0x01)
|
||||
self._send_command(0xC3, 0x15)
|
||||
self._send_command(0xC4, 0x20)
|
||||
self._send_command(0xC6, 0x0F)
|
||||
self._send_command(0xD0, 0xA4, 0xA1)
|
||||
self._send_command(
|
||||
0xE0,
|
||||
0xD0,
|
||||
0x08,
|
||||
0x0E,
|
||||
0x09,
|
||||
0x09,
|
||||
0x05,
|
||||
0x31,
|
||||
0x33,
|
||||
0x48,
|
||||
0x17,
|
||||
0x14,
|
||||
0x15,
|
||||
0x31,
|
||||
0x34,
|
||||
)
|
||||
self._send_command(
|
||||
0xE1,
|
||||
0xD0,
|
||||
0x08,
|
||||
0x0E,
|
||||
0x09,
|
||||
0x09,
|
||||
0x15,
|
||||
0x31,
|
||||
0x33,
|
||||
0x48,
|
||||
0x17,
|
||||
0x14,
|
||||
0x15,
|
||||
0x31,
|
||||
0x34,
|
||||
)
|
||||
self._send_command(0x21)
|
||||
self._send_command(0x29)
|
||||
|
||||
def _send_command(self, cmd, *args):
|
||||
GPIO.output(self.DC_PIN, GPIO.LOW)
|
||||
self.spi.xfer2([cmd])
|
||||
if args:
|
||||
GPIO.output(self.DC_PIN, GPIO.HIGH)
|
||||
self._send_data(list(args))
|
||||
|
||||
def _send_data(self, data):
|
||||
GPIO.output(self.DC_PIN, GPIO.HIGH)
|
||||
|
||||
try:
|
||||
|
||||
self.spi.writebytes2(data)
|
||||
except AttributeError:
|
||||
max_chunk = 4096
|
||||
for i in range(0, len(data), max_chunk):
|
||||
self.spi.writebytes(data[i : i + max_chunk])
|
||||
|
||||
def set_window(self, x0, y0, x1, y1, use_horizontal=0):
|
||||
if use_horizontal in (0, 1):
|
||||
self._send_command(0x2A, x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF)
|
||||
self._send_command(
|
||||
0x2B, (y0 + 20) >> 8, (y0 + 20) & 0xFF, (y1 +
|
||||
20) >> 8, (y1 + 20) & 0xFF
|
||||
)
|
||||
elif use_horizontal in (2, 3):
|
||||
self._send_command(
|
||||
0x2A, (x0 + 20) >> 8, (x0 + 20) & 0xFF, (x1 +
|
||||
20) >> 8, (x1 + 20) & 0xFF
|
||||
)
|
||||
self._send_command(0x2B, y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF)
|
||||
self._send_command(0x2C)
|
||||
|
||||
def draw_pixel(self, x, y, color):
|
||||
if x >= self.LCD_WIDTH or y >= self.LCD_HEIGHT:
|
||||
return
|
||||
self.set_window(x, y, x, y)
|
||||
self._send_data([(color >> 8) & 0xFF, color & 0xFF])
|
||||
|
||||
def draw_line(self, x0, y0, x1, y1, color):
|
||||
dx = abs(x1 - x0)
|
||||
dy = abs(y1 - y0)
|
||||
sx = 1 if x0 < x1 else -1
|
||||
sy = 1 if y0 < y1 else -1
|
||||
err = dx - dy
|
||||
|
||||
while True:
|
||||
self.draw_pixel(x0, y0, color)
|
||||
if x0 == x1 and y0 == y1:
|
||||
break
|
||||
e2 = 2 * err
|
||||
if e2 > -dy:
|
||||
err -= dy
|
||||
x0 += sx
|
||||
if e2 < dx:
|
||||
err += dx
|
||||
y0 += sy
|
||||
|
||||
def fill_screen(self, color):
|
||||
self.set_window(0, 0, self.LCD_WIDTH - 1, self.LCD_HEIGHT - 1)
|
||||
buffer = []
|
||||
high = (color >> 8) & 0xFF
|
||||
low = color & 0xFF
|
||||
for _ in range(self.LCD_WIDTH * self.LCD_HEIGHT):
|
||||
buffer.extend([high, low])
|
||||
self._send_data(buffer)
|
||||
|
||||
def draw_image(self, x, y, width, height, pixel_data):
|
||||
if (x + width > self.LCD_WIDTH) or (y + height > self.LCD_HEIGHT):
|
||||
raise ValueError("图像尺寸超出屏幕范围")
|
||||
self.set_window(x, y, x + width - 1, y + height - 1)
|
||||
self._send_data(pixel_data)
|
||||
|
||||
# ========== RGB 与按键 ==========
|
||||
def set_rgb(self, r, g, b):
|
||||
if self.red_pwm is None or self.green_pwm is None or self.blue_pwm is None:
|
||||
return
|
||||
try:
|
||||
self.red_pwm.ChangeDutyCycle(100 - (r / 255 * 100))
|
||||
self.green_pwm.ChangeDutyCycle(100 - (g / 255 * 100))
|
||||
self.blue_pwm.ChangeDutyCycle(100 - (b / 255 * 100))
|
||||
self._current_r = r
|
||||
self._current_g = g
|
||||
self._current_b = b
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not set RGB: {e}")
|
||||
|
||||
def set_rgb_fade(self, r_target, g_target, b_target, duration_ms=100):
|
||||
steps = 20 # 可以调整步数来控制渐变的平滑度
|
||||
delay_ms = duration_ms / steps
|
||||
|
||||
r_step = (r_target - self._current_r) / steps
|
||||
g_step = (g_target - self._current_g) / steps
|
||||
b_step = (b_target - self._current_b) / steps
|
||||
|
||||
for _ in range(steps + 1):
|
||||
r_interim = int(self._current_r + _ * r_step)
|
||||
g_interim = int(self._current_g + _ * g_step)
|
||||
b_interim = int(self._current_b + _ * b_step)
|
||||
self.set_rgb(
|
||||
max(0, min(255, r_interim)),
|
||||
max(0, min(255, g_interim)),
|
||||
max(0, min(255, b_interim)),
|
||||
)
|
||||
time.sleep(delay_ms / 1000.0)
|
||||
|
||||
def button_pressed(self):
|
||||
return GPIO.input(self.BUTTON_PIN) == 1
|
||||
|
||||
def on_button_press(self, callback):
|
||||
self.button_press_callback = callback
|
||||
|
||||
def on_button_release(self, callback):
|
||||
self.button_release_callback = callback
|
||||
|
||||
def _button_release_event(self, channel):
|
||||
if self.button_release_callback:
|
||||
self.button_release_callback()
|
||||
|
||||
def _button_press_event(self, channel):
|
||||
if self.button_press_callback:
|
||||
self.button_press_callback()
|
||||
|
||||
def _button_event(self, channel):
|
||||
# 按下是5V,松开是0V
|
||||
if not self._gpio_initialized:
|
||||
return
|
||||
try:
|
||||
if GPIO.input(channel):
|
||||
# Falling edge (按钮按下)
|
||||
self._button_press_event(channel)
|
||||
else:
|
||||
# Rising edge (按钮释放)
|
||||
self._button_release_event(channel)
|
||||
except Exception as e:
|
||||
print(f"Warning: Button event error: {e}")
|
||||
|
||||
# ========== 清理 ==========
|
||||
def cleanup(self):
|
||||
# 清理代码中添加对 backlight_pwm 的处理
|
||||
if self.backlight_pwm is not None:
|
||||
self.backlight_pwm.stop()
|
||||
self.spi.close()
|
||||
self.red_pwm.stop()
|
||||
self.green_pwm.stop()
|
||||
self.blue_pwm.stop()
|
||||
GPIO.cleanup()
|
||||
111
pwnagotchi/ui/hw/whisplay.py
Normal file
111
pwnagotchi/ui/hw/whisplay.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import logging
|
||||
import os
|
||||
import importlib.util
|
||||
import numpy as np
|
||||
|
||||
import pwnagotchi.ui.fonts as fonts
|
||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||
|
||||
class Whisplay(DisplayImpl):
|
||||
def __init__(self, config):
|
||||
super(Whisplay, self).__init__(config, 'whisplay')
|
||||
self._display = None
|
||||
|
||||
def layout(self):
|
||||
fonts.setup(10, 9, 10, 35, 25, 9)
|
||||
# Update layout to match 280x240 display
|
||||
self._layout['width'] = 240
|
||||
self._layout['height'] = 280
|
||||
self._layout['face'] = (0, 35)
|
||||
self._layout['name'] = (20, 0)
|
||||
self._layout['channel'] = (5, 15)
|
||||
self._layout['aps'] = (33, 15)
|
||||
self._layout['uptime'] = (195, 15)
|
||||
# extend line positions to the new width
|
||||
self._layout['line1'] = [0, 30, 280, 30]
|
||||
self._layout['line2'] = [0, 220, 280, 220]
|
||||
self._layout['friend_face'] = (0, 92)
|
||||
self._layout['friend_name'] = (40, 94)
|
||||
self._layout['shakes'] = (17, 223)
|
||||
self._layout['mode'] = (235, 223)
|
||||
self._layout['status'] = {
|
||||
'pos': (140, 35),
|
||||
'font': fonts.status_font(fonts.Medium),
|
||||
'max': 20
|
||||
}
|
||||
|
||||
|
||||
return self._layout
|
||||
|
||||
def initialize(self):
|
||||
logging.info("Initializing Whisplay with PiSugar WhisPlayBoard driver")
|
||||
# Pins (physical BOARD numbering) for this wiring/setup:
|
||||
logging.info("5V pins: physical 2 and 4")
|
||||
logging.info("GND: any GND pin")
|
||||
logging.info("I2C SDA (SDA) = physical pin 3")
|
||||
logging.info("I2C SCL (SCL) = physical pin 5")
|
||||
logging.info("LCD control / Backlight = physical pin 15")
|
||||
logging.info("SPI SCLK = physical pin 23, MOSI = physical pin 19, CS (CE0) = physical pin 24")
|
||||
logging.info("SPI D/C = physical pin 13, SPI RST = physical pin 7")
|
||||
logging.info("I2S pins (physical): WS=35, DIN=38, DOUT=40")
|
||||
# Instantiate the WhisPlayBoard driver
|
||||
from pwnagotchi.ui.hw.libs.whisplay.whisplaydriver import WhisPlayBoard
|
||||
self._display = WhisPlayBoard()
|
||||
self._display.set_rgb(0, 0, 0)
|
||||
self._display.set_backlight(50)
|
||||
|
||||
def render(self, canvas):
|
||||
"""Render canvas to display by converting to RGB565 and sending via draw_image."""
|
||||
screen_width = self._display.LCD_WIDTH
|
||||
screen_height = self._display.LCD_HEIGHT
|
||||
|
||||
# Convert canvas to PIL Image if it's a numpy array
|
||||
if isinstance(canvas, np.ndarray):
|
||||
img = Image.fromarray(canvas.astype('uint8'))
|
||||
else:
|
||||
img = canvas.convert('RGB')
|
||||
|
||||
# Get original dimensions and calculate aspect ratios
|
||||
original_width, original_height = img.size
|
||||
aspect_ratio = original_width / original_height
|
||||
screen_aspect_ratio = screen_width / screen_height
|
||||
|
||||
# Scale and crop to maintain aspect ratio while filling screen
|
||||
if aspect_ratio > screen_aspect_ratio:
|
||||
# Original image is wider, scale based on screen height
|
||||
new_height = screen_height
|
||||
new_width = int(new_height * aspect_ratio)
|
||||
resized_img = img.resize((new_width, new_height))
|
||||
# Calculate horizontal offset to center the image
|
||||
offset_x = (new_width - screen_width) // 2
|
||||
# Crop the image to fit screen width
|
||||
cropped_img = resized_img.crop(
|
||||
(offset_x, 0, offset_x + screen_width, screen_height))
|
||||
else:
|
||||
# Original image is taller or has the same aspect ratio, scale based on screen width
|
||||
new_width = screen_width
|
||||
new_height = int(new_width / aspect_ratio)
|
||||
resized_img = img.resize((new_width, new_height))
|
||||
# Calculate vertical offset to center the image
|
||||
offset_y = (new_height - screen_height) // 2
|
||||
# Crop the image to fit screen height
|
||||
cropped_img = resized_img.crop(
|
||||
(0, offset_y, screen_width, offset_y + screen_height))
|
||||
|
||||
# Convert to RGB565 pixel data with 40-pixel top padding
|
||||
pixel_data = []
|
||||
|
||||
# Add the actual image data (reduced height due to padding)
|
||||
for y in range(screen_height):
|
||||
for x in range(screen_width):
|
||||
r, g, b = cropped_img.getpixel((x, y))
|
||||
# Convert RGB to RGB565 (5-6-5 bits)
|
||||
rgb565 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
|
||||
pixel_data.extend([(rgb565 >> 8) & 0xFF, rgb565 & 0xFF])
|
||||
|
||||
# Draw the image on the display (back to 0, 0 without offset)
|
||||
self._display.draw_image(0, 0, screen_width, screen_height, pixel_data)
|
||||
|
||||
def clear(self):
|
||||
"""Clear the display (fill with black)."""
|
||||
self._display.fill_screen(0)
|
||||
@@ -218,6 +218,8 @@ def load_config(args):
|
||||
config['ui']['display']['type'] = 'dummydisplay'
|
||||
|
||||
# NON E-INK DISPLAYS---------------------------------------------------------------
|
||||
elif config['ui']['display']['type'] in 'whisplay':
|
||||
config['ui']['display']['type'] = 'whisplay'
|
||||
elif config['ui']['display']['type'] in ('wavesharelcd0in96', 'wslcd0in96'):
|
||||
config['ui']['display']['type'] = 'wavesharelcd0in96'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user