mirror of
https://github.com/ayufan/steam-deck-tools.git
synced 2026-04-04 22:07:40 +00:00
Extend performance overlay to include FT and others
This commit is contained in:
parent
059d64827f
commit
01f0d6b366
21 changed files with 198 additions and 63 deletions
|
|
@ -16,6 +16,10 @@
|
|||
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CommonHelpers\CommonHelpers.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Settings.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using FanControl.FromLibreHardwareMonitor;
|
||||
using CommonHelpers.FromLibreHardwareMonitor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
|
@ -17,7 +17,10 @@ namespace FanControl
|
|||
public partial class FanControlForm : Form
|
||||
{
|
||||
private FanController fanControl = new FanController();
|
||||
private StartupManager startupManager = new StartupManager();
|
||||
private StartupManager startupManager = new StartupManager(
|
||||
"Steam Deck Fan Control",
|
||||
"Starts Steam Deck Fan Control on Windows startup."
|
||||
);
|
||||
|
||||
public FanControlForm()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Diagnostics.Metrics;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CommonHelpers;
|
||||
|
||||
namespace FanControl
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace FanControl
|
|||
FanMode.Max, new FanSensor.Profile()
|
||||
{
|
||||
Type = FanSensor.Profile.ProfileType.Constant,
|
||||
MinRPM = Vlv0100.MAX_FAN_RPM
|
||||
MinRPM = CommonHelpers.Vlv0100.MAX_FAN_RPM
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Security.Principal;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using Action = Microsoft.Win32.TaskScheduler.Action;
|
||||
using Task = Microsoft.Win32.TaskScheduler.Task;
|
||||
|
||||
namespace FanControl.FromLibreHardwareMonitor
|
||||
{
|
||||
public class StartupManager
|
||||
{
|
||||
private const string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
private bool _startup;
|
||||
|
||||
public const string Description = "Starts Steam Deck Fan Control on Windows startup.";
|
||||
public const string NameOf = "Steam Deck Fan Control";
|
||||
|
||||
public StartupManager()
|
||||
{
|
||||
if (Environment.OSVersion.Platform >= PlatformID.Unix)
|
||||
{
|
||||
IsAvailable = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAdministrator() && TaskService.Instance.Connected)
|
||||
{
|
||||
IsAvailable = true;
|
||||
|
||||
Task task = GetTask();
|
||||
if (task != null)
|
||||
{
|
||||
foreach (Action action in task.Definition.Actions)
|
||||
{
|
||||
if (action.ActionType == TaskActionType.Execute && action is ExecAction execAction)
|
||||
{
|
||||
if (execAction.Path.Equals(Application.ExecutablePath, StringComparison.OrdinalIgnoreCase))
|
||||
_startup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(RegistryPath))
|
||||
{
|
||||
string value = (string)registryKey?.GetValue(NameOf);
|
||||
|
||||
if (value != null)
|
||||
_startup = value == Application.ExecutablePath;
|
||||
}
|
||||
|
||||
IsAvailable = true;
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
IsAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAvailable { get; }
|
||||
|
||||
public bool Startup
|
||||
{
|
||||
get { return _startup; }
|
||||
set
|
||||
{
|
||||
if (_startup != value)
|
||||
{
|
||||
if (IsAvailable)
|
||||
{
|
||||
if (TaskService.Instance.Connected)
|
||||
{
|
||||
if (value)
|
||||
CreateTask();
|
||||
else
|
||||
DeleteTask();
|
||||
|
||||
_startup = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (value)
|
||||
CreateRegistryKey();
|
||||
else
|
||||
DeleteRegistryKey();
|
||||
|
||||
_startup = value;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAdministrator()
|
||||
{
|
||||
try
|
||||
{
|
||||
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
||||
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
||||
|
||||
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Task GetTask()
|
||||
{
|
||||
try
|
||||
{
|
||||
return TaskService.Instance.AllTasks.FirstOrDefault(x => x.Name.Equals(NameOf, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTask()
|
||||
{
|
||||
TaskDefinition taskDefinition = TaskService.Instance.NewTask();
|
||||
taskDefinition.RegistrationInfo.Description = Description;
|
||||
|
||||
taskDefinition.Triggers.Add(new LogonTrigger());
|
||||
|
||||
taskDefinition.Settings.StartWhenAvailable = true;
|
||||
taskDefinition.Settings.DisallowStartIfOnBatteries = false;
|
||||
taskDefinition.Settings.StopIfGoingOnBatteries = false;
|
||||
taskDefinition.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||
taskDefinition.Settings.AllowHardTerminate = false;
|
||||
|
||||
taskDefinition.Principal.RunLevel = TaskRunLevel.Highest;
|
||||
taskDefinition.Principal.LogonType = TaskLogonType.InteractiveToken;
|
||||
|
||||
taskDefinition.Actions.Add(new ExecAction(Application.ExecutablePath, "", Path.GetDirectoryName(Application.ExecutablePath)));
|
||||
|
||||
TaskService.Instance.RootFolder.RegisterTaskDefinition(NameOf, taskDefinition);
|
||||
}
|
||||
|
||||
private static void DeleteTask()
|
||||
{
|
||||
Task task = GetTask();
|
||||
task?.Folder.DeleteTask(task.Name, false);
|
||||
}
|
||||
|
||||
private static void CreateRegistryKey()
|
||||
{
|
||||
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath);
|
||||
registryKey?.SetValue(NameOf, Application.ExecutablePath);
|
||||
}
|
||||
|
||||
private static void DeleteRegistryKey()
|
||||
{
|
||||
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath);
|
||||
registryKey?.DeleteValue(NameOf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FanControl
|
||||
{
|
||||
internal class InpOut
|
||||
{
|
||||
[DllImport("inpoutx64.dll", EntryPoint = "MapPhysToLin", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern IntPtr MapPhysToLin(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle);
|
||||
|
||||
[DllImport("inpoutx64.dll", EntryPoint = "UnmapPhysicalMemory", CallingConvention = CallingConvention.StdCall)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr);
|
||||
|
||||
[DllImport("inpoutx64.dll", EntryPoint = "DlPortReadPortUchar", CallingConvention = CallingConvention.StdCall)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
public static extern byte DlPortReadPortUchar(ushort port);
|
||||
|
||||
[DllImport("inpoutx64.dll", EntryPoint = "DlPortWritePortUchar", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern byte DlPortWritePortUchar(ushort port, byte vlaue);
|
||||
|
||||
public static byte[] ReadMemory(IntPtr baseAddress, uint size)
|
||||
{
|
||||
IntPtr pdwLinAddr = MapPhysToLin(baseAddress, size, out IntPtr pPhysicalMemoryHandle);
|
||||
if (pdwLinAddr != IntPtr.Zero)
|
||||
{
|
||||
byte[] bytes = new byte[size];
|
||||
Marshal.Copy(pdwLinAddr, bytes, 0, bytes.Length);
|
||||
UnmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool WriteMemory(IntPtr baseAddress, byte[] data)
|
||||
{
|
||||
IntPtr pdwLinAddr = MapPhysToLin(baseAddress, (uint)data.Length, out IntPtr pPhysicalMemoryHandle);
|
||||
if (pdwLinAddr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Copy(data, 0, pdwLinAddr, data.Length);
|
||||
UnmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using CommonHelpers;
|
||||
|
||||
namespace FanControl
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FanControl
|
||||
{
|
||||
internal class Vlv0100
|
||||
{
|
||||
// Those addresses are taken from DSDT for VLV0100
|
||||
// and might change at any time with a BIOS update
|
||||
// Purpose: https://lore.kernel.org/lkml/20220206022023.376142-1-andrew.smirnov@gmail.com/
|
||||
// Addresses: DSDT.txt
|
||||
static IntPtr FSLO_FSHI = new IntPtr(0xFE700B00 + 0x92);
|
||||
static IntPtr GNLO_GNHI = new IntPtr(0xFE700B00 + 0x95);
|
||||
static IntPtr FRPR = new IntPtr(0xFE700B00 + 0x97);
|
||||
static IntPtr FNRL_FNRH = new IntPtr(0xFE700300 + 0xB0);
|
||||
static IntPtr FNCK = new IntPtr(0xFE700300 + 0x9F);
|
||||
static IntPtr BATH_BATL = new IntPtr(0xFE700400 + 0x6E);
|
||||
static IntPtr PDFV = new IntPtr(0xFE700C00 + 0x4C);
|
||||
static IntPtr XBID = new IntPtr(0xFE700300 + 0xBD);
|
||||
static IntPtr PDCT = new IntPtr(0xFE700C00 + 0x01);
|
||||
static ushort IO6C = 0x6C;
|
||||
|
||||
public const ushort MAX_FAN_RPM = 0x1C84;
|
||||
|
||||
public static readonly ushort[] SupportedFirmwares = {
|
||||
0xB030 // 45104
|
||||
};
|
||||
|
||||
public static readonly byte[] SupportedBoardID = {
|
||||
6
|
||||
};
|
||||
|
||||
public static readonly byte[] SupportedPDCS = {
|
||||
0x2B // 43
|
||||
};
|
||||
|
||||
public static bool IsSupported()
|
||||
{
|
||||
var firmwareVersion = GetFirmwareVersion();
|
||||
var boardID = GetBoardID();
|
||||
var pdcs = GetPDCS();
|
||||
|
||||
return SupportedFirmwares.Contains(firmwareVersion) &&
|
||||
SupportedBoardID.Contains(boardID);
|
||||
}
|
||||
|
||||
public static ushort GetFirmwareVersion()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(PDFV, 2);
|
||||
return BitConverter.ToUInt16(data);
|
||||
}
|
||||
|
||||
public static byte GetBoardID()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(XBID, 1);
|
||||
return data[0];
|
||||
}
|
||||
|
||||
public static byte GetPDCS()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(PDCT, 1);
|
||||
return data[0];
|
||||
}
|
||||
|
||||
public static ushort GetFanDesiredRPM()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(FSLO_FSHI, 2);
|
||||
return BitConverter.ToUInt16(data);
|
||||
}
|
||||
|
||||
public static ushort GetFanRPM()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(FNRL_FNRH, 2);
|
||||
return BitConverter.ToUInt16(data);
|
||||
}
|
||||
public static void SetFanControl(Boolean userControlled)
|
||||
{
|
||||
SetGain(10);
|
||||
SetRampRate(userControlled ? (byte)10 : (byte)20);
|
||||
|
||||
InpOut.DlPortWritePortUchar(IO6C, userControlled ? (byte)0xCC : (byte)0xCD);
|
||||
}
|
||||
|
||||
public static void SetFanDesiredRPM(ushort rpm)
|
||||
{
|
||||
if (rpm > MAX_FAN_RPM)
|
||||
rpm = MAX_FAN_RPM;
|
||||
|
||||
byte[] data = BitConverter.GetBytes(rpm);
|
||||
InpOut.WriteMemory(FSLO_FSHI, data);
|
||||
}
|
||||
|
||||
public static bool GetFanCheck()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(FNCK, 1);
|
||||
return (data[0] & 0x1) != 0;
|
||||
}
|
||||
|
||||
public static float GetBattTemperature()
|
||||
{
|
||||
byte[] data = InpOut.ReadMemory(BATH_BATL, 2);
|
||||
int value = (data[0] << 8) + data[1];
|
||||
return (float)(value - 0x0AAC) / 10.0f;
|
||||
}
|
||||
|
||||
private static void SetGain(ushort gain)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(gain);
|
||||
InpOut.WriteMemory(GNLO_GNHI, data);
|
||||
}
|
||||
private static void SetRampRate(byte rampRate)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(rampRate);
|
||||
InpOut.WriteMemory(FRPR, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue