diff --git a/UXTU4Linux/Assets/Modules/device_presets_loader.py b/UXTU4Linux/Assets/Modules/device_presets_loader.py new file mode 100644 index 0000000..b775ab3 --- /dev/null +++ b/UXTU4Linux/Assets/Modules/device_presets_loader.py @@ -0,0 +1,76 @@ +import json +import os +import subprocess + +_PRESETS_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), "device_presets.json") +_PRESETS_CACHE = None + +def _load_presets(): + global _PRESETS_CACHE + if _PRESETS_CACHE is not None: + return _PRESETS_CACHE + try: + if os.path.exists(_PRESETS_FILE): + with open(_PRESETS_FILE, "r") as f: + data = json.load(f) + _PRESETS_CACHE = data.get("devices", []) + return _PRESETS_CACHE + except Exception: + pass + return [] + +def _has_discrete_gpu(gpu_flag: str) -> bool: + try: + result = subprocess.run( + ["lspci"], + capture_output=True, text=True, timeout=5, + ) + lines = [l for l in result.stdout.splitlines() if "VGA" in l or "Display" in l] + vga = "\n".join(lines).lower() + return gpu_flag.lower() in vga + except Exception: + return False + +def match_device(manufacturer: str, product_name: str) -> str: + devices = _load_presets() + mfr_lower = manufacturer.lower() + prod_lower = product_name.lower() + + for device in devices: + # Check manufacturer + if "manufacturer_contains" in device: + if device["manufacturer_contains"].lower() not in mfr_lower: + continue + + # Check product name ALL (AND condition) + if "product_name_contains" in device: + reqs = device["product_name_contains"] + if isinstance(reqs, list): + if not all(r.lower() in prod_lower for r in reqs): + continue + elif isinstance(reqs, str): + if reqs.lower() not in prod_lower: + continue + + # Check product name ANY (OR condition) + if "product_name_contains_any" in device: + reqs = device["product_name_contains_any"] + if isinstance(reqs, list): + if not any(r.lower() in prod_lower for r in reqs): + continue + + # Check discrete GPU requirement + if "requires_discrete_gpu" in device: + if not _has_discrete_gpu(device["requires_discrete_gpu"]): + continue + + return device.get("variant_name", "") + + return "" + +def get_device_preset(variant_name: str) -> dict | None: + devices = _load_presets() + for device in devices: + if device.get("variant_name") == variant_name: + return device.get("preset") + return None diff --git a/UXTU4Linux/Assets/Modules/hardware.py b/UXTU4Linux/Assets/Modules/hardware.py index 00844ed..ff80578 100644 --- a/UXTU4Linux/Assets/Modules/hardware.py +++ b/UXTU4Linux/Assets/Modules/hardware.py @@ -381,40 +381,12 @@ def _cpu_type(family: str, arch: str) -> str: return "Amd_Apu" -def _lspci_vga() -> str: - try: - result = subprocess.run( - ["lspci"], - capture_output=True, text=True, timeout=5, - ) - lines = [l for l in result.stdout.splitlines() if "VGA" in l or "Display" in l] - return "\n".join(lines).lower() - except Exception: - return "" - - -def _has_discrete_rx7700s() -> bool: - vga = _lspci_vga() - return "7700s" in vga or "rx 7700s" in vga - - -def _detect_framework_variant() -> str: +def _detect_device_variant() -> str: + from .device_presets_loader import match_device sys_raw = _dmi_raw("system") - product = _extract(sys_raw, "Product Name").lower() - mfr = _extract(sys_raw, "Manufacturer").lower() - - if "framework" not in mfr: - return "" - - if "laptop 16" in product and "7040" in product: - if _has_discrete_rx7700s(): - return "AMDFrameworkLaptop16Ryzen7040_RX7700S" - return "AMDFrameworkLaptop16Ryzen7040" - - if "laptop 13" in product and ("7040" in product or "ai 300" in product or "ryzen ai 300" in product): - return "AMDFrameworkLaptop13Ryzen7040_RyzenAI300" - - return "" + product = _extract(sys_raw, "Product Name") + mfr = _extract(sys_raw, "Manufacturer") + return match_device(mfr, product) def detect() -> None: @@ -423,7 +395,7 @@ def detect() -> None: cfg.set_config("Info", key, _dmi(field)) _compute_codename() - variant = _detect_framework_variant() + variant = _detect_device_variant() cfg.set_config("Info", "Variant", variant) cfg.save() diff --git a/UXTU4Linux/Assets/Modules/presets.py b/UXTU4Linux/Assets/Modules/presets.py index 7044067..c301d93 100644 --- a/UXTU4Linux/Assets/Modules/presets.py +++ b/UXTU4Linux/Assets/Modules/presets.py @@ -110,28 +110,17 @@ def get_preset(cpu_type: str, family: str, cpu_model: str, raw_cpu: str, variant def _variant_preset(variant: str) -> Preset | None: - match variant: - case "AMDFrameworkLaptop16Ryzen7040_RX7700S": - return Preset( - Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=30000 --fast-limit=35000 --slow-limit=30000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=95000 --fast-limit=95000 --slow-limit=95000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=100000 --fast-limit=100000 --slow-limit=120000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=120000 --fast-limit=140000 --slow-limit=120000 --vrm-current=200000 --vrmmax-current=200000 --vrmsoc-current=200000 --vrmsocmax-current=200000 --vrmgfx-current=200000", - ) - case "AMDFrameworkLaptop16Ryzen7040": - return Preset( - Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=6000 --fast-limit=8000 --slow-limit=6000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=45000 --slow-limit=38000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=45000 --fast-limit=55000 --slow-limit=50000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=55000 --fast-limit=70000 --slow-limit=65000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - ) - case "AMDFrameworkLaptop13Ryzen7040_RyzenAI300": - return Preset( - Eco="--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=8000 --fast-limit=10000 --slow-limit=8000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Balance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=15000 --fast-limit=18000 --slow-limit=15000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Performance="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=28000 --fast-limit=42000 --slow-limit=28000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - Extreme="--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=60000 --slow-limit=35000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", - ) + from .device_presets_loader import get_device_preset + preset_data = get_device_preset(variant) + if preset_data: + return Preset( + Eco=preset_data.get("Eco", ""), + Balance=preset_data.get("Balance", ""), + Performance=preset_data.get("Performance", ""), + Extreme=preset_data.get("Extreme", ""), + AC=preset_data.get("AC", "--max-performance"), + DC=preset_data.get("DC", "--power-saving") + ) return None diff --git a/UXTU4Linux/Assets/device_presets.json b/UXTU4Linux/Assets/device_presets.json new file mode 100644 index 0000000..01f65f3 --- /dev/null +++ b/UXTU4Linux/Assets/device_presets.json @@ -0,0 +1,39 @@ +{ + "devices": [ + { + "manufacturer_contains": "framework", + "product_name_contains": ["laptop 16", "7040"], + "requires_discrete_gpu": "7700s", + "variant_name": "AMDFrameworkLaptop16Ryzen7040_RX7700S", + "preset": { + "Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=30000 --fast-limit=35000 --slow-limit=30000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=95000 --fast-limit=95000 --slow-limit=95000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=100000 --fast-limit=100000 --slow-limit=120000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=120000 --fast-limit=140000 --slow-limit=120000 --vrm-current=200000 --vrmmax-current=200000 --vrmsoc-current=200000 --vrmsocmax-current=200000 --vrmgfx-current=200000" + } + }, + { + "manufacturer_contains": "framework", + "product_name_contains": ["laptop 16", "7040"], + "variant_name": "AMDFrameworkLaptop16Ryzen7040", + "preset": { + "Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=6000 --fast-limit=8000 --slow-limit=6000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=45000 --slow-limit=38000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=45000 --fast-limit=55000 --slow-limit=50000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=55000 --fast-limit=70000 --slow-limit=65000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000" + } + }, + { + "manufacturer_contains": "framework", + "product_name_contains": ["laptop 13"], + "product_name_contains_any": ["7040", "ai 300", "ryzen ai 300"], + "variant_name": "AMDFrameworkLaptop13Ryzen7040_RyzenAI300", + "preset": { + "Eco": "--tctl-temp=100 --apu-skin-temp=45 --stapm-limit=8000 --fast-limit=10000 --slow-limit=8000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Balance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=15000 --fast-limit=18000 --slow-limit=15000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Performance": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=28000 --fast-limit=42000 --slow-limit=28000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000", + "Extreme": "--tctl-temp=100 --apu-skin-temp=50 --stapm-limit=35000 --fast-limit=60000 --slow-limit=35000 --vrm-current=180000 --vrmmax-current=180000 --vrmsoc-current=180000 --vrmsocmax-current=180000 --vrmgfx-current=180000" + } + } + ] +}