Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

trofeo-lcd

Python driver for the Thermalright Trofeo Vision 11.3 LCD USB panel (0416:5408, "USBDISPLAY", 1920x440 framebuffer). The frame protocol was reverse-engineered from USB captures of the vendor's TRCC software and verified byte-for-byte against them. There is no official software for Linux/macOS; this library fills that gap.

Installation

From GitHub (no manual cloning needed, pip handles it):

pip install "git+https://github.com/surrounds/trofeo-lcd.git"

Line for another project's requirements.txt:

trofeo-lcd @ git+https://github.com/surrounds/trofeo-lcd.git

From a local folder (e.g. for development):

pip install /path/to/trofeo-lcd          # or -e for editable

Dependencies: pyusb, pillow. libusb must be present on the system (macOS: brew install libusb, Debian/Ubuntu: apt install libusb-1.0-0). Permissions: on Linux add a udev rule for 0416:5408 (MODE="0666"), otherwise run as root.

Usage

from PIL import Image, ImageDraw
from trofeo_lcd import TrofeoPanel, WIDTH, HEIGHT
import time

img = Image.new("RGB", (WIDTH, HEIGHT), (10, 12, 20))
ImageDraw.Draw(img).text((40, 40), "Hello, panel!", fill=(255, 255, 255))

with TrofeoPanel.open() as panel:
    while True:                 # see "Watchdog" below
        panel.send_image(img)
        time.sleep(1.0)

A resilient loop with recovery:

import time
from trofeo_lcd import TrofeoPanel

panel = None
while True:
    try:
        if panel is None:
            panel = TrofeoPanel.open()
        panel.send_image(render())          # your 1920x440 PIL image
    except Exception as e:
        print(f"error: {e}")
        if panel is not None:
            panel.recover(hard=True)
            panel.close()
            panel = None
        time.sleep(2)
    time.sleep(1.0)

API

  • TrofeoPanel.open(quiet=False) - find and open the panel (context manager, closes itself)
  • panel.send_image(pil_img, quality=85) - send a PIL image; resizes to 1920x440/RGB, encodes and pads automatically
  • panel.send_frame(jpeg, field) - low level: send a pre-padded JPEG
  • panel.recover(hard=False) - clear endpoint halts, drain buffers, with hard=True also perform a USB reset
  • panel.drain_in() - drain heartbeat packets (send_image already does this after every frame)
  • find_device() - locate the device without opening it
  • Protocol helpers: frame_field(len), pad_jpeg_com(jpeg), build_chunks(jpeg, field), encode_frame(img), constants WIDTH, HEIGHT, TARGET_LEN

Non-default VID/PID: environment variables TV_VID / TV_PID.

Hardware quirks you must know

  • Watchdog: without a fresh frame the panel reverts to the factory logo after 1-2 seconds. Send frames in a loop at ~1s intervals.
  • The firmware hangs on a malformed stream (write timeout on the first blocks) and only a physical cable replug revives it; a USB reset does not help. Never change the protocol constants or formulas.
  • JPEG must be baseline 4:2:0 (encode_frame produces the right bitstream). Progressive or 4:4:4 JPEG hangs the firmware.
  • The panel emits a heartbeat packet on the IN endpoint every ~2s; the library drains it after every frame.
  • The device needs no handshake, and sending one is harmful: any extra packet breaks the stream alignment.

Frame format (for the curious)

A frame is 524 blocks of 512 bytes: a 16-byte header (01 ff + u16 field + a constant + u32 block number) followed by 496 bytes of JPEG data. Transport slicing: bulk writes of 65x4096 plus one 2048. The JPEG is padded with COM segments up to 258507 bytes (the length of TRCC's reference frame), which makes the field 0xF1CB. The field depends only on the JPEG length: frame_field() was recovered from 19 frames across two independent captures.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages