Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 83 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ High-performance, lightweight, zero-bloat hardware control suite for Acer gaming
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![.NET 10](https://img.shields.io/badge/.NET-10.0-512BD4.svg)](https://dotnet.microsoft.com/)
[![NativeAOT](https://img.shields.io/badge/Runtime-NativeAOT-success.svg)]()
[![Platform](https://img.shields.io/badge/Platform-Windows-lightgrey.svg)]()
[![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux-lightgrey.svg)]()

</div>

---

> [!WARNING]
> **Work in Progress Notice:**
> - **Graphical User Interface (GUI)**: The standalone GUI client is currently under active development. The background service daemon (`openpredator-service`) and CLI utility (`openpredator`) should be fully functional.
> - **Linux Support**: Basic Linux abstractions exist in `Core`, but active development and physical testing for Linux are on the back burner for now.
> - **Graphical User Interface (GUI)**: The standalone GUI client is currently under active development. The background service daemon (`openpredator-service`) and CLI utility (`openpredator`) are fully functional.
> - **Linux Support**: Linux hardware control (ACPI WMI, fans, telemetry, and power modes) is functional and verified on physical hardware. However, installation and service setup are currently manual (standalone binaries work; automated installers are planned).

---

Expand Down Expand Up @@ -47,7 +47,7 @@ OpenPredator's daemon is also wire-compatible with the OEM named pipe interface
| :--- | :---: | :--- |
| Windows 11 | ✅ | Tested on Windows 11 (25H2) |
| Windows 10 | ❓ | Expected working (uses identical ACPI WMI drivers) |
| Linux | 🚧 | In active development (ACPI backend and Unix sockets implemented; physical testing in progress) |
| Linux | ✅ | Tested on MX Linux (23.6). Manual binary deployment for now. |

---

Expand Down Expand Up @@ -131,44 +131,107 @@ openpredator config apply

---

## Linux Support & Manual Setup

Linux support is fully implemented and verified on real hardware, providing real-time hardware telemetry, fan speed and curve control, power modes, and keyboard backlight management through ACPI firmware calls. While automated packaging (e.g., `.deb`/`.rpm` or systemd service packages) is planned, binaries are fully usable right now with manual execution.

### 1. Prerequisites (Kernel Modules)
OpenPredator communicates directly with Acer ACPI WMI tables on Linux via `/proc/acpi/call` and decompresses the BIOS BMOF table via `wmi-bmof`.

**Debian / Ubuntu / MX Linux / Linux Mint:**
```bash
sudo apt update && sudo apt install -y acpi-call-dkms
sudo modprobe acpi_call
sudo modprobe wmi-bmof

# Verify interfaces are loaded:
ls -l /proc/acpi/call
ls -l /sys/bus/wmi/devices/*/bmof
```

**Fedora / RHEL:**
```bash
sudo dnf install -y akmod-acpi_call
sudo modprobe acpi_call
sudo modprobe wmi-bmof
```

**Arch Linux:**
```bash
sudo pacman -S acpi_call-dkms
sudo modprobe acpi_call
sudo modprobe wmi-bmof
```

### 2. Running OpenPredator on Linux

#### Option A: Background Service + Unprivileged CLI / GUI (Recommended)
Run the service daemon as root. It creates a Unix domain socket (`/tmp/predatorsense_service_namedpipe`) with open permissions (`0666`) and caches discovered WMI methods to `~/.config/openpredator/wmi_methods.json`, allowing non-root users and desktop sessions to interact with hardware safely without `sudo`:

```bash
# Terminal 1: Start the service daemon
sudo ./openpredator-service

# Terminal 2: Run commands as a regular user
./openpredator watch # Live dashboard
./openpredator fan max # 100% fan speed
./openpredator fan auto -c # Auto curve with CoolBoost
./openpredator mode perf # Switch power mode
./openpredator-gui # Desktop GUI
```

#### Option B: Standalone CLI (Direct Hardware Access)
If the background service is not running, the CLI can interact with hardware directly, but requires root privileges to write to `/proc/acpi/call`:

```bash
sudo ./openpredator status
sudo ./openpredator fan max
sudo ./openpredator fan auto
sudo ./openpredator coolboost on
sudo ./openpredator mode perf
sudo ./openpredator watch
```

---

## Building from Source

### Prerequisites
- [.NET 10.0 SDK](https://dotnet.microsoft.com/)
- Visual Studio 2022 Desktop development with C++ (required for NativeAOT compilation on Windows)
- Native compilation toolchain (required for NativeAOT: Visual Studio C++ on Windows; `clang`, `build-essential`, `zlib1g-dev` on Linux)
- [Inno Setup 6](https://jrsoftware.org/isdl.php) (optional, for compiling Windows installer package)

### Build Pipeline (`builder`)

OpenPredator features a cross-platform, zero-dependency C# build runner located in `builder/`. You can invoke it via the root wrappers (`build.bat` on Windows, `./build.sh` on Linux) or `dotnet run --project builder`:
OpenPredator features a cross-platform, zero-dependency C# build runner located in `builder/`. You can invoke it via the root wrappers (`./build` / `build.bat` on Windows, `./build` / `./build.sh` on Linux) or `dotnet run --project builder`:

```cmd
```bash
# 1. Release build for current OS (dist/<rid>/) - excludes test suite
build.bat
# or: build.bat all
./build
# or: ./build all

# 2. Release build + package Windows Setup Installer (dist/installer/)
build.bat installer
./build installer

# 3. Release build + package Portable standalone ZIP (dist/portable/)
build.bat portable
# 3. Release build + package Portable standalone archive (dist/portable/)
./build portable

# 4. Full Release Packaging (Installer + Portable ZIP + SHA256SUMS manifest)
build.bat pack
# 4. Full Release Packaging (Installer + Portable archive + SHA256SUMS manifest)
./build pack

# 5. Development debug build with interactive Testing Suite included
build.bat dev
./build dev

# 6. Clean all build outputs, .temp caches, and bin/obj directories
build.bat clean
./build clean

# 7. Version management
build.bat version # Inspect current version
build.bat version 1.0.1 # Bump version across build props & installer
./build version # Inspect current version
./build version 1.0.1 # Bump version across build props & installer

# 8. Explicit OS target prefixes
build.bat windows:pack
build.bat linux:all
./build windows:pack
./build linux:all
```

---
Expand Down
27 changes: 6 additions & 21 deletions builder/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ private static void PrintHelp()
Console.WriteLine(" pack Full release packaging (Installer + Portable ZIP + SHA256SUMS)");
Console.WriteLine(" dev Debug build including test suite (openpredator-testsuite)");
Console.WriteLine(" clean Clean all dist/, .temp/, artifacts/, bin/, and obj/ directories");
Console.WriteLine(" version [new_ver] Inspect or bump version across Directory.Build.props & Inno Setup");
Console.WriteLine(" version [new_ver] Inspect or bump version in Directory.Build.props (auto-propagated to binaries & installer)");
Console.WriteLine(" help Display this help screen\n");
Console.WriteLine("Target Prefix & Targeted Build Examples:");
Console.WriteLine(" build project:Gui Quick release build of OpenPredator.Gui -> dist/win-x64/");
Expand Down Expand Up @@ -578,7 +578,6 @@ private static async Task<int> BuildProjectCommandAsync(string targetProject, st
private static int HandleVersionCommand(string? newVersion)
{
string propsPath = Path.Combine(RootDir, "Directory.Build.props");
string issPath = Path.Combine(RootDir, "builder", "OpenPredatorSetup.iss");

if (string.IsNullOrWhiteSpace(newVersion))
{
Expand All @@ -588,14 +587,9 @@ private static int HandleVersionCommand(string? newVersion)
var content = File.ReadAllText(propsPath);
var mVer = System.Text.RegularExpressions.Regex.Match(content, @"<Version>(.*?)</Version>");
var mAss = System.Text.RegularExpressions.Regex.Match(content, @"<AssemblyVersion>(.*?)</AssemblyVersion>");
Console.WriteLine($" Directory.Build.props : Version={mVer.Groups[1].Value}, AssemblyVersion={mAss.Groups[1].Value}");
}
if (File.Exists(issPath))
{
var content = File.ReadAllText(issPath);
var mIss = System.Text.RegularExpressions.Regex.Match(content, @"#define MyAppVersion ""(.*?)""");
var mInfo = System.Text.RegularExpressions.Regex.Match(content, @"VersionInfoVersion=(.*)");
Console.WriteLine($" OpenPredatorSetup.iss : MyAppVersion={mIss.Groups[1].Value}, VersionInfoVersion={mInfo.Groups[1].Value}");
var mFile = System.Text.RegularExpressions.Regex.Match(content, @"<FileVersion>(.*?)</FileVersion>");
Console.WriteLine($" Directory.Build.props : Version={mVer.Groups[1].Value}, AssemblyVersion={mAss.Groups[1].Value}, FileVersion={mFile.Groups[1].Value}");
Console.WriteLine($" OpenPredatorSetup.iss : (Inherits dynamically via /DMyAppVersion & /DVersionInfoVersion during build)");
}
Console.WriteLine("\n\x1b[90mTo update version: build version <new_version> (e.g. 1.0.1 or 1.0.1.1)\x1b[0m\n");
return 0;
Expand Down Expand Up @@ -632,7 +626,7 @@ private static int HandleVersionCommand(string? newVersion)

Console.WriteLine($"\x1b[1;36m>>> Updating Project Version to {semVer} ({fourPartVer})...\x1b[0m\n");

// 1. Update Directory.Build.props
// 1. Update Directory.Build.props (Single Source of Truth)
if (File.Exists(propsPath))
{
string content = File.ReadAllText(propsPath);
Expand All @@ -643,16 +637,7 @@ private static int HandleVersionCommand(string? newVersion)
Console.WriteLine($"\x1b[1;32m[OK]\x1b[0m Updated {Path.GetRelativePath(RootDir, propsPath)}");
}

// 2. Update OpenPredatorSetup.iss
if (File.Exists(issPath))
{
string content = File.ReadAllText(issPath);
content = System.Text.RegularExpressions.Regex.Replace(content, @"#define MyAppVersion "".*?""", $"#define MyAppVersion \"{semVer}\"");
content = System.Text.RegularExpressions.Regex.Replace(content, @"VersionInfoVersion=.*", $"VersionInfoVersion={fourPartVer}");
File.WriteAllText(issPath, content);
Console.WriteLine($"\x1b[1;32m[OK]\x1b[0m Updated {Path.GetRelativePath(RootDir, issPath)}");
}

Console.WriteLine($"\x1b[1;32m[OK]\x1b[0m OpenPredatorSetup.iss dynamically inherits from build props at compile time.");
Console.WriteLine($"\n\x1b[1;32m[Success]\x1b[0m All version fields updated to: \x1b[1;37m{semVer}\x1b[0m (Assembly/File: \x1b[1;36m{fourPartVer}\x1b[0m)\n");
return 0;
}
Expand Down
11 changes: 11 additions & 0 deletions src/OpenPredator.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ public static async Task<int> Main(string[] args)
bool connected = await client.ConnectAsync(1500);
if (!connected)
{
if (cmd != "config" && !ProcessElevation.IsElevated)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[Notice] Background daemon (OpenPredator Service / OEM PSSvc) is not active on pipe.");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[Error] Direct hardware access requires elevated privileges (Administrator on Windows, sudo/root on Linux).");
Console.ResetColor();
Console.WriteLine(" Please start the service (e.g. 'sudo openpredator-service' or Windows Service) or run this command with elevation.\n");
return 1;
}

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[Notice] No background daemon (OpenPredator Service / OEM PSSvc) active on pipe.");
Console.WriteLine(" Falling back to direct hardware access (ACPI WMI + SMBIOS + NVML)...\n");
Expand Down
Loading
Loading