Skip to content

Commit 218a545

Browse files
committed
feat(lcd): Add support for Solarmax / HL-VMAX (Artinchip VID 0x33C3 PID 0xF101) displays
- Added LcdCommVmax driver supporting USB CDC serial protocol - Added automatic geometry descriptor parsing (462x1920, 320x1480, 480x1920) - Implemented thread-safe in-memory canvas buffering and frame queue rate-limiting - Configured CDC serial parameters (rtscts=False, dtr=True, rts=True) for reliable handshake - Patched GPUtil and Windows process execution with CREATE_NO_WINDOW - Added unit tests, test script, configure.py model support, and documentation
1 parent 2e060fa commit 218a545

12 files changed

Lines changed: 506 additions & 29 deletions

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ Supported operating systems : macOS, Windows, Linux (incl. Raspberry Pi), basica
2626
| <img src="res/docs/xuanfang.webp"/> | <img src="res/docs/UsbPCMonitor_5inch.webp" width="60%" height="60%"/> | <img src="res/docs/kipye-qiye-35.webp" width="60%" height="60%"/> |
2727
| revision B & flagship (with backplate & RGB LEDs) | Unknown manufacturer, visually similar to Turing 3.5" / 5". Original software is `UsbPCMonitor.exe` | Front panel has an engraved inscription "奇叶智显" Qiye Zhixian (Qiye Smart Display) |
2828

29-
| ✅ WeAct Studio Display FS V1 0.96" | ✅ WeAct Studio Display FS V1 3.5" |
30-
|---------------------------------------------------------------|--------------------------------------------------------------|
31-
| <img src="res/docs/weact_0.96.jpg" width="60%" height="60%"/> | <img src="res/docs/weact_3.5.png" width="60%" height="60%"/> |
29+
| ✅ WeAct Studio Display FS V1 0.96" | ✅ WeAct Studio Display FS V1 3.5" | ✅ Solarmax / HL-VMAX (Artinchip) |
30+
|---------------------------------------------------------------|--------------------------------------------------------------|---------------------------------------------------------------|
31+
| <img src="res/docs/weact_0.96.jpg" width="60%" height="60%"/> | <img src="res/docs/weact_3.5.png" width="60%" height="60%"/> | Ultra-wide PC case & secondary displays (320x1480, 462x1920) |
3232

3333
<details>
3434

config.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ config:
1010
# Theme to use (located in res/themes)
1111
# Use the name of the folder as value
1212
# Choose a theme made for your screen size (see DISPLAY_SIZE inside theme.yaml)
13-
THEME: 3.5inchTheme2
13+
THEME: "Cyberpunk 2077 Vertical"
1414

1515
# Hardware sensors reading
1616
# Choose the appropriate method for reading your hardware sensors:
1717
# - PYTHON use Python libraries (psutils, GPUtil...) to read hardware sensors (supports all OS but not all HW)
1818
# - LHM use LibreHardwareMonitor library to read hardware sensors (Windows only - NEEDS ADMIN RIGHTS)
1919
# - STUB / STATIC use random/static data instead of real hardware sensors
2020
# - AUTO use the best method based on your OS: Windows OS will use LHM, other OS will use Python libraries
21-
HW_SENSORS: AUTO
21+
HW_SENSORS: PYTHON
2222

2323
# Network interfaces
2424
# Linux/MacOS interfaces are named "eth0", "wlan0", "wlp1s0", "enp2s0"...
@@ -59,14 +59,15 @@ display:
5959
# - TUR_USB for Turing HW revisions 1.x: 4.6"/5.2"/8.0"/8.8"/9.2"
6060
# - WEACT_A for WeAct Studio Display FS V1 3.5"
6161
# - WEACT_B for WeAct Studio Display FS V1 0.96"
62+
# - VMAX for Solarmax / HL-VMAX (Artinchip VID 0x33C3 PID 0xF101)
6263
# - SIMU for simulated display (image written in screencap.png). Width & height will be detected from the theme
6364
# To identify your smart screen: https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions
64-
REVISION: A
65+
REVISION: VMAX
6566

6667
# Display Brightness
6768
# Set this as the desired %, 0 being completely dark and 100 being max brightness
6869
# Warning: revision A display can get hot at high brightness!
69-
BRIGHTNESS: 20
70+
BRIGHTNESS: 80
7071

7172
# Display reverse: true/false
7273
# Set to true to reverse display orientation (landscape <-> reverse landscape, portrait <-> reverse portrait)
@@ -77,4 +78,4 @@ display:
7778
# By default, this program resets the display on startup, in case it is in a degraded state from previous runs.
7879
# This behavior causes the display to disconnect/reconnect, and the COM port to change.
7980
# On some displays (like rev. A) it can be an issue, in this case change the value to "false".
80-
RESET_ON_STARTUP: true
81+
RESET_ON_STARTUP: false

configure.py

100755100644
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
XUANFANG_MODEL = "XuanFang rev. B & flagship"
6464
KIPYE_MODEL = "Kipye Qiye Smart Display"
6565
WEACT_MODEL = "WeAct Studio Display FS V1"
66+
SOLARMAX_MODEL = "Solarmax / HL-VMAX (Artinchip)"
6667
SIMULATED_MODEL = "Simulated screen"
6768

6869
_SIZE_2_1_INCH = "2.1\"" # Only for retro compatibility
@@ -77,6 +78,7 @@
7778
SIZE_8_INCH = "8\""
7879
SIZE_8_8_INCH = "8.8\""
7980
SIZE_8_8_INCH_NEWREV = "8.8\" / 9.2\" (V1.X new HW rev.)"
81+
SIZE_11_3_INCH = "11.3\" / 9.2\" (320x1480 / 462x1920)"
8082
SIZE_12_3_INCH = "12.3\""
8183
SIZE_2_8_INCH_NEWREV = "2.8\" round (V1.X new HW rev.)"
8284

@@ -92,6 +94,7 @@
9294
SIZE_8_INCH,
9395
SIZE_8_8_INCH,
9496
SIZE_8_8_INCH_NEWREV,
97+
SIZE_11_3_INCH,
9598
SIZE_12_3_INCH,
9699
)
97100

@@ -114,6 +117,9 @@
114117
('TUR_USB', SIZE_2_8_INCH_NEWREV): TURING_MODEL,
115118
('WEACT_A', SIZE_3_5_INCH): WEACT_MODEL,
116119
('WEACT_B', SIZE_0_96_INCH): WEACT_MODEL,
120+
('VMAX', SIZE_11_3_INCH): SOLARMAX_MODEL,
121+
('VMAX', SIZE_8_8_INCH): SOLARMAX_MODEL,
122+
('VMAX', SIZE_8_8_INCH_NEWREV): SOLARMAX_MODEL,
117123

118124
('SIMU', SIZE_0_96_INCH): SIMULATED_MODEL,
119125
('SIMU', SIZE_2_x_INCH): SIMULATED_MODEL,
@@ -123,10 +129,14 @@
123129
('SIMU', SIZE_5_2_INCH): SIMULATED_MODEL,
124130
('SIMU', SIZE_8_INCH): SIMULATED_MODEL,
125131
('SIMU', SIZE_8_8_INCH): SIMULATED_MODEL,
132+
('SIMU', SIZE_11_3_INCH): SIMULATED_MODEL,
126133
}
127134
# This map is used to write the correct config.yaml "REVISION" from selected smart screen model and size
128135
model_and_size_to_revision_map = {
129136
(KIPYE_MODEL, SIZE_3_5_INCH): 'D',
137+
(SOLARMAX_MODEL, SIZE_11_3_INCH): 'VMAX',
138+
(SOLARMAX_MODEL, SIZE_8_8_INCH): 'VMAX',
139+
(SOLARMAX_MODEL, SIZE_8_8_INCH_NEWREV): 'VMAX',
130140
(TURING_MODEL, SIZE_2_x_INCH): 'C',
131141
(TURING_MODEL, SIZE_3_5_INCH): 'A',
132142
(TURING_MODEL, SIZE_4_6_INCH): 'TUR_USB',
@@ -151,6 +161,7 @@
151161
(SIMULATED_MODEL, SIZE_5_2_INCH): 'SIMU',
152162
(SIMULATED_MODEL, SIZE_8_INCH): 'SIMU',
153163
(SIMULATED_MODEL, SIZE_8_8_INCH): 'SIMU',
164+
(SIMULATED_MODEL, SIZE_11_3_INCH): 'SIMU',
154165
}
155166
hw_lib_map = {"AUTO": "Automatic", "LHM": "LibreHardwareMonitor (admin.)", "PYTHON": "Python libraries",
156167
"STUB": "Fake random data", "STATIC": "Fake static data"}
@@ -606,7 +617,7 @@ def on_theme_editor_click(self):
606617
# Load binary (for releases) or Python file with system interpreter
607618
theme_editor = next(MAIN_DIRECTORY.glob("theme-editor*"))
608619
if platform.system() == "Windows":
609-
subprocess.Popen([str(theme_editor), self.theme_cb.get()], shell=True)
620+
subprocess.Popen([str(theme_editor), self.theme_cb.get()], creationflags=0x08000000)
610621
else:
611622
subprocess.Popen([str(theme_editor), self.theme_cb.get()])
612623

@@ -624,7 +635,7 @@ def on_saverun_click(self):
624635
# Load binary (for releases) or Python file with system interpreter
625636
main_file = next(MAIN_DIRECTORY.glob("main*"))
626637
if platform.system() == "Windows":
627-
subprocess.Popen([str(main_file)], shell=True)
638+
subprocess.Popen([str(main_file)], creationflags=0x08000000)
628639
else:
629640
subprocess.Popen([str(main_file)])
630641

library/display.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from library.lcd.lcd_comm_rev_d import LcdCommRevD
2828
from library.lcd.lcd_comm_weact_a import LcdCommWeActA
2929
from library.lcd.lcd_comm_weact_b import LcdCommWeActB
30+
from library.lcd.lcd_comm_vmax import LcdCommVmax
3031
from library.lcd.lcd_simulated import LcdSimulated
3132
from library.log import logger
3233

@@ -76,6 +77,8 @@ def _get_theme_size() -> tuple[int, int]:
7677
return 480, 1920
7778
elif config.THEME_DATA["display"].get("DISPLAY_SIZE", '') == '9.2"':
7879
return 480, 1920 # 9.2" displays are 1920x462 but using 1920x480 to be compatible with 8.8" themes
80+
elif config.THEME_DATA["display"].get("DISPLAY_SIZE", '') == '11.3"':
81+
return 320, 1480
7982
elif config.THEME_DATA["display"].get("DISPLAY_SIZE", '') == '12.3"':
8083
return 720, 1920
8184
else:
@@ -109,6 +112,9 @@ def __init__(self):
109112
elif config.CONFIG_DATA["display"]["REVISION"] == "WEACT_B":
110113
self.lcd = LcdCommWeActB(com_port=config.CONFIG_DATA['config']['COM_PORT'],
111114
update_queue=config.update_queue)
115+
elif config.CONFIG_DATA["display"]["REVISION"] in ("VMAX", "SOLARMAX"):
116+
self.lcd = LcdCommVmax(com_port=config.CONFIG_DATA['config']['COM_PORT'],
117+
update_queue=config.update_queue, display_width=width, display_height=height)
112118
elif config.CONFIG_DATA["display"]["REVISION"] == "SIMU":
113119
# Simulated display: always set width/height from theme
114120
self.lcd = LcdSimulated(display_width=width, display_height=height)

0 commit comments

Comments
 (0)