Skip to content

Commit a7e1c30

Browse files
committed
ZenTune
1 parent de4c822 commit a7e1c30

43 files changed

Lines changed: 1049 additions & 1006 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

UXTU4Linux/Assets/core/hardware.py

Lines changed: 0 additions & 423 deletions
This file was deleted.

UXTU4Linux/Assets/tui/tabs/infoView.py

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,32 @@
55
from configparser import ConfigParser
66
from pathlib import Path
77

8-
LOCAL_VERSION = "1.2.0"
9-
LOCAL_BUILD = "M1-beta-30Jun26-r2"
8+
from Assets.core.platform import RUNTIME_DIR
109

11-
GITHUB_API_URL = "https://api.github.com/repos/HorizonUnix/UXTU4Linux/releases/latest"
12-
LATEST_VER_URL = "https://github.com/HorizonUnix/UXTU4Linux/releases/latest"
13-
RYZEN_SMU_WIKI_URL = "https://github.com/HorizonUnix/UXTU4Linux/wiki/Linux-Installation#2-install-ryzen_smu-secure-boot-only"
14-
DMIDECODE_WIKI_URL = "https://github.com/HorizonUnix/UXTU4Linux/wiki/Linux-Installation#3-install-uxtu4linux"
10+
LOCAL_VERSION = "2.0.0"
11+
LOCAL_BUILD = "R1-03Jul26"
12+
13+
APP_NAME = "zentune"
14+
DIST_NAME = "ZenTune"
15+
16+
GITHUB_API_URL = "https://api.github.com/repos/HorizonUnix/ZenTune/releases/latest"
17+
LATEST_VER_URL = "https://github.com/HorizonUnix/ZenTune/releases/latest"
18+
RYZEN_SMU_WIKI_URL = "https://github.com/HorizonUnix/ZenTune/wiki/Linux-Installation#2-install-ryzen_smu-secure-boot-only"
1519

1620
_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
1721
ASSETS_DIR = os.path.join(_ROOT, "Assets")
22+
REQUIREMENTS_PATH = os.path.join(_ROOT, "requirements.txt")
1823

1924
CONFIG_PATH = os.path.join(ASSETS_DIR, "config.ini")
2025
CUSTOM_PRESETS_PATH = Path(ASSETS_DIR) / "custom.json"
2126
ADAPTIVE_PRESETS_PATH = os.path.join(ASSETS_DIR, "adaptive.json")
2227

23-
DMIDECODE = "dmidecode"
2428
KERNEL = os.uname().sysname
2529

26-
VENV_DIR = "/opt/uxtu4linux/venv"
30+
VENV_DIR = "/opt/zentune/venv"
2731
VENV_PYTHON = os.path.join(VENV_DIR, "bin", "python3")
2832

29-
ZMQ_SOCKET_PATH = "/run/uxtu4linux.sock"
33+
ZMQ_SOCKET_PATH = f"{RUNTIME_DIR}/{APP_NAME}.sock"
3034
ZMQ_SOCKET_ADDR = f"ipc://{ZMQ_SOCKET_PATH}"
3135

3236
MIN_INTERVAL_SECONDS: int = 1
@@ -130,7 +134,7 @@ def instance() -> ConfigParser:
130134
REQUIRED: dict[str, list[str]] = {
131135
"User": ["mode"],
132136
"Settings": ["time", "reapply", "applyonstart", "autostartadaptive", "softwareupdate", "debug", "defaulttab"],
133-
"Info": ["cpu", "signature", "architecture", "family", "type", "variant", "maxclock"],
137+
"Info": ["cpu", "signature", "architecture", "family", "type", "variant"],
134138
"Automations": ["onac", "onbattery", "onresume"],
135139
"Adaptive": ["preset", "interval"],
136140
}

ZenTune/Assets/core/hardware.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
from __future__ import annotations
2+
3+
import os, subprocess
4+
5+
from Assets.core import config as cfg
6+
from Assets.core import platform as plat
7+
from zenmaster.smu import secure_boot_enabled
8+
9+
10+
PROC_CPUINFO = "/proc/cpuinfo"
11+
SYS_CPUFREQ_MAX = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
12+
SYS_DMI_ID_DIR = "/sys/class/dmi/id"
13+
14+
15+
def _cpuinfo_dict() -> dict[str, str]:
16+
result: dict[str, str] = {}
17+
try:
18+
with open(PROC_CPUINFO) as f:
19+
for line in f:
20+
if ":" not in line:
21+
if line.strip() == "" and result:
22+
break
23+
continue
24+
key, _, value = line.partition(":")
25+
result[key.strip()] = value.strip()
26+
except OSError:
27+
pass
28+
return result
29+
30+
31+
def max_clock_mhz() -> int:
32+
if plat.IS_MACOS:
33+
hz = _sysctl_int("hw.cpufrequency_max")
34+
if hz <= 0:
35+
return 0
36+
mhz = hz // 1_000_000
37+
return ((mhz + 499) // 500) * 500
38+
try:
39+
with open(SYS_CPUFREQ_MAX) as f:
40+
khz = int(f.read().strip())
41+
return ((khz // 1000 + 499) // 500) * 500
42+
except (OSError, ValueError):
43+
pass
44+
try:
45+
mhz = float(_cpuinfo_dict().get("cpu MHz", "0"))
46+
except ValueError:
47+
mhz = 0
48+
if mhz <= 0:
49+
return 0
50+
return ((int(mhz) + 499) // 500) * 500
51+
52+
53+
_SMU_INSTALL_GUIDE = f"Install guide: {cfg.RYZEN_SMU_WIKI_URL}"
54+
55+
56+
def check_ryzen_smu() -> str | None:
57+
if not secure_boot_enabled():
58+
return None
59+
60+
from zenmaster.smu import module_status
61+
62+
st = module_status()
63+
if st.ok:
64+
return None
65+
66+
if st.reason == "unknown":
67+
message = (
68+
f"ryzen_smu is loaded but its version cannot be determined "
69+
f"(minimum required: {st.min_version})"
70+
)
71+
elif st.reason == "too_old":
72+
message = f"ryzen_smu version {st.version} is too old (minimum required: {st.min_version})"
73+
elif st.reason == "not_installed":
74+
message = "ryzen_smu kernel module is not installed"
75+
elif st.reason == "unsigned":
76+
message = "ryzen_smu is installed but not signed for Secure Boot"
77+
else:
78+
message = "ryzen_smu is installed but not loaded"
79+
80+
return f"{message}.\n\n{_SMU_INSTALL_GUIDE}"
81+
82+
83+
def _read_sysfs(path: str) -> str | None:
84+
try:
85+
with open(path) as f:
86+
return f.read().strip()
87+
except OSError:
88+
return None
89+
90+
91+
def _parse_device_info() -> dict[str, str]:
92+
return {
93+
"name": _read_sysfs(os.path.join(SYS_DMI_ID_DIR, "product_name")) or "N/A",
94+
"producer": _read_sysfs(os.path.join(SYS_DMI_ID_DIR, "sys_vendor")) or "N/A",
95+
"model": _read_sysfs(os.path.join(SYS_DMI_ID_DIR, "board_name")) or "N/A",
96+
}
97+
98+
99+
def _lspci_vga() -> str:
100+
try:
101+
result = subprocess.run(
102+
["lspci"],
103+
capture_output=True, text=True, timeout=5,
104+
)
105+
lines = [l for l in result.stdout.splitlines() if "VGA" in l or "Display" in l]
106+
return "\n".join(lines).lower()
107+
except Exception:
108+
return ""
109+
110+
111+
def _has_discrete_rx7700s() -> bool:
112+
vga = _lspci_vga()
113+
return "7700s" in vga or "rx 7700s" in vga
114+
115+
116+
def _sysctl_int(name: str) -> int:
117+
try:
118+
out = subprocess.run(["sysctl", "-n", name], capture_output=True, text=True, timeout=5)
119+
except (OSError, subprocess.SubprocessError):
120+
return 0
121+
try:
122+
return int(out.stdout.strip())
123+
except ValueError:
124+
return 0
125+
126+
127+
def _detect_framework_variant() -> str:
128+
product = (_read_sysfs(os.path.join(SYS_DMI_ID_DIR, "product_name")) or "").lower()
129+
mfr = (_read_sysfs(os.path.join(SYS_DMI_ID_DIR, "sys_vendor")) or "").lower()
130+
131+
if "framework" not in mfr:
132+
return ""
133+
134+
if "laptop 16" in product and "7040" in product:
135+
if _has_discrete_rx7700s():
136+
return "AMDFrameworkLaptop16Ryzen7040_RX7700S"
137+
return "AMDFrameworkLaptop16Ryzen7040"
138+
139+
if "laptop 13" in product and ("7040" in product or "ai 300" in product or "ryzen ai 300" in product):
140+
return "AMDFrameworkLaptop13Ryzen7040_RyzenAI300"
141+
142+
return ""
143+
144+
145+
_detected_family_cache: str | None = None
146+
147+
148+
def detected_family() -> str:
149+
global _detected_family_cache
150+
if _detected_family_cache is None:
151+
from zenmaster.hardware import detect as zm_detect
152+
_detected_family_cache = zm_detect().family
153+
return _detected_family_cache
154+
155+
156+
def detect() -> None:
157+
from zenmaster.hardware import detect as zm_detect
158+
info = zm_detect()
159+
cfg.set_config("Info", "CPU", info.name or "Unknown")
160+
cfg.set_config("Info", "Signature",
161+
f"Family {info.cpu_family_int}, Model {info.cpu_model_int}, Stepping {info.cpu_stepping_int}")
162+
_compute_codename(info)
163+
164+
variant = _detect_framework_variant()
165+
cfg.set_config("Info", "Variant", variant)
166+
167+
cfg.save()
168+
169+
170+
def _compute_codename(info=None) -> None:
171+
if info is None:
172+
raw_cpu = cfg.get("Info", "CPU")
173+
signature = cfg.get("Info", "Signature")
174+
try:
175+
words = signature.split()
176+
cpu_family = int(words[words.index("Family") + 1].rstrip(","))
177+
cpu_model = int(words[words.index("Model") + 1].rstrip(","))
178+
except (ValueError, IndexError):
179+
cfg.set_config("Info", "Architecture", "Unknown")
180+
cfg.set_config("Info", "Family", "Unknown")
181+
cfg.set_config("Info", "Type", "Unknown")
182+
return
183+
from zenmaster.hardware import resolve
184+
info = resolve(raw_cpu, cpu_family, cpu_model)
185+
186+
from zenmaster.runner import is_supported
187+
cpu_type = info.type
188+
if cpu_type in ("Amd_Apu", "Amd_Desktop_Cpu") and not is_supported(info.family):
189+
cpu_type = "Unknown"
190+
cfg.set_config("Info", "Architecture", info.arch)
191+
cfg.set_config("Info", "Family", info.family)
192+
cfg.set_config("Info", "Type", cpu_type)
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,6 @@ def apply_saved(self) -> dict:
9292
return self._send({"cmd": "apply_saved"}) \
9393
or {"ok": False, "error": "daemon not responding"}
9494

95-
def dmidecode(self, dmi_type: str) -> str:
96-
r = self._send({"cmd": "dmidecode", "type": dmi_type})
97-
if r and r.get("ok"):
98-
return r["output"]
99-
return ""
100-
10195
def reload_config(self) -> dict:
10296
return self._send({"cmd": "reload_config"}) or {"ok": False}
10397

ZenTune/Assets/core/platform.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from __future__ import annotations
2+
3+
import platform as _platform
4+
5+
IS_MACOS = _platform.system() == "Darwin"
6+
IS_LINUX = _platform.system() == "Linux"
7+
8+
RUNTIME_DIR = "/var/run" if IS_MACOS else "/run"

0 commit comments

Comments
 (0)