152 lines
5.7 KiB
Python
152 lines
5.7 KiB
Python
import machine
|
|
import st7789py as st7789
|
|
from config import CURRENT_CONFIG
|
|
import font
|
|
|
|
class Display:
|
|
def __init__(self):
|
|
self.tft = None
|
|
self.width = 240
|
|
self.height = 240
|
|
self._init_display()
|
|
self.font = font.Font()
|
|
|
|
def _init_display(self):
|
|
print(">>> Initializing Display...")
|
|
try:
|
|
pins = CURRENT_CONFIG.pins
|
|
spi = machine.SPI(2, baudrate=40000000, polarity=1, phase=1,
|
|
sck=machine.Pin(pins['sck']), mosi=machine.Pin(pins['mosi']))
|
|
|
|
cs_pin = pins.get('cs')
|
|
cs = machine.Pin(cs_pin, machine.Pin.OUT) if cs_pin is not None else None
|
|
|
|
rst_pin = pins.get('rst')
|
|
dc_pin = pins.get('dc')
|
|
|
|
self.tft = st7789.ST7789(spi, self.width, self.height,
|
|
reset=machine.Pin(rst_pin, machine.Pin.OUT) if rst_pin else None,
|
|
dc=machine.Pin(dc_pin, machine.Pin.OUT) if dc_pin else None,
|
|
cs=cs,
|
|
backlight=None)
|
|
self.tft.init()
|
|
self.tft.fill(st7789.BLUE)
|
|
except Exception as e:
|
|
print(f"Display error: {e}")
|
|
self.tft = None
|
|
|
|
def fill(self, color):
|
|
if self.tft:
|
|
self.tft.fill(color)
|
|
|
|
def fill_rect(self, x, y, w, h, color):
|
|
if self.tft:
|
|
self.tft.fill_rect(x, y, w, h, color)
|
|
|
|
def set_ws(self, ws):
|
|
if self.font:
|
|
self.font.set_ws(ws)
|
|
|
|
def text(self, text, x, y, color, wait=True):
|
|
if self.tft:
|
|
self.font.text(self.tft, text, x, y, color, wait=wait)
|
|
|
|
def init_ui(self):
|
|
"""初始化 UI 背景"""
|
|
if self.tft:
|
|
self.tft.fill(st7789.BLACK)
|
|
self.tft.fill_rect(0, 0, 240, 30, st7789.WHITE)
|
|
|
|
def update_audio_bar(self, bar_height, last_bar_height):
|
|
"""更新音频可视化的柱状图"""
|
|
if not self.tft: return last_bar_height
|
|
|
|
# 确定当前颜色
|
|
color = st7789.GREEN
|
|
if bar_height > 50: color = st7789.YELLOW
|
|
if bar_height > 100: color = st7789.RED
|
|
|
|
# 确定上一次颜色
|
|
last_color = st7789.GREEN
|
|
if last_bar_height > 50: last_color = st7789.YELLOW
|
|
if last_bar_height > 100: last_color = st7789.RED
|
|
|
|
# 1. 如果变矮了,清除顶部多余部分
|
|
if bar_height < last_bar_height:
|
|
self.tft.fill_rect(100, 240 - last_bar_height, 40, last_bar_height - bar_height, st7789.BLACK)
|
|
|
|
# 2. 如果颜色变了,必须重绘整个条
|
|
if color != last_color:
|
|
self.tft.fill_rect(100, 240 - bar_height, 40, bar_height, color)
|
|
# 3. 如果颜色没变且变高了,只绘新增部分
|
|
elif bar_height > last_bar_height:
|
|
self.tft.fill_rect(100, 240 - bar_height, 40, bar_height - last_bar_height, color)
|
|
|
|
return bar_height
|
|
|
|
def show_image(self, x, y, width, height, rgb565_data):
|
|
"""在指定位置显示RGB565格式的图片数据"""
|
|
if not self.tft: return
|
|
|
|
try:
|
|
# 将字节数据转换为适合blit_buffer的格式
|
|
self.tft.blit_buffer(rgb565_data, x, y, width, height)
|
|
except Exception as e:
|
|
print(f"Show image error: {e}")
|
|
|
|
def show_image_chunk(self, x, y, width, height, data, offset):
|
|
"""流式显示图片数据块"""
|
|
if not self.tft: return
|
|
|
|
# ST7789 blit_buffer expects a complete buffer for the window
|
|
# But we can calculate which pixels this chunk corresponds to
|
|
|
|
# This is tricky because blit_buffer sets a window and then writes data.
|
|
# If we want to stream, we should probably set the window once and then write chunks.
|
|
# But st7789py library might not expose raw write easily without window set.
|
|
|
|
# Alternative: Calculate the sub-window for this chunk.
|
|
# Data is a linear sequence of pixels (2 bytes per pixel)
|
|
# We assume data length is even.
|
|
|
|
try:
|
|
# Simple approach: If offset is 0, we set the window for the whole image
|
|
# And then write data. But st7789py's blit_buffer does both.
|
|
|
|
# Let's look at st7789py implementation.
|
|
# fill_rect sets window then writes.
|
|
# blit_buffer sets window then writes.
|
|
|
|
# We can use a modified approach:
|
|
# If it's the first chunk, set window.
|
|
# Then write data.
|
|
|
|
# But we can't easily modify the library state from here.
|
|
# So we calculate the rect for this chunk.
|
|
|
|
# Total pixels
|
|
total_pixels = width * height
|
|
|
|
# Current pixel offset
|
|
pixel_offset = offset // 2
|
|
num_pixels = len(data) // 2
|
|
|
|
# This only works if chunks align with rows, or if we can write partial rows.
|
|
# ST7789 supports writing continuous memory.
|
|
|
|
# Let's try to determine the x, y, w, h for this chunk.
|
|
# This is complex if it wraps around lines.
|
|
|
|
# Easier approach for ESP32 memory constrained environment:
|
|
# We just need to use the raw write method of the display driver if available.
|
|
|
|
if offset == 0:
|
|
# Set window for the whole image
|
|
self.tft.set_window(x, y, x + width - 1, y + height - 1)
|
|
|
|
# Write raw data
|
|
self.tft.write(None, data)
|
|
|
|
except Exception as e:
|
|
print(f"Show chunk error: {e}")
|