LenovoLegionToolkit

Форк
0
372 строки · 15.6 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Threading.Tasks;
5
using LenovoLegionToolkit.Lib.Extensions;
6
using LenovoLegionToolkit.Lib.Settings;
7
using LenovoLegionToolkit.Lib.SoftwareDisabler;
8
using LenovoLegionToolkit.Lib.System.Management;
9
using LenovoLegionToolkit.Lib.Utils;
10

11
namespace LenovoLegionToolkit.Lib.Controllers.GodMode;
12

13
public class GodModeControllerV2 : AbstractGodModeController
14
{
15
    public GodModeControllerV2(GodModeSettings settings, VantageDisabler vantageDisabler, LegionZoneDisabler legionZoneDisabler) : base(settings, vantageDisabler, legionZoneDisabler) { }
16

17
    public override Task<bool> NeedsVantageDisabledAsync() => Task.FromResult(true);
18
    public override Task<bool> NeedsLegionZoneDisabledAsync() => Task.FromResult(true);
19

20
    public override async Task ApplyStateAsync()
21
    {
22
        if (await VantageDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
23
        {
24
            if (Log.Instance.IsTraceEnabled)
25
                Log.Instance.Trace($"Can't correctly apply state when Vantage is running.");
26
            return;
27
        }
28

29
        if (await LegionZoneDisabler.GetStatusAsync().ConfigureAwait(false) == SoftwareStatus.Enabled)
30
        {
31
            if (Log.Instance.IsTraceEnabled)
32
                Log.Instance.Trace($"Can't correctly apply state when Legion Zone is running.");
33
            return;
34
        }
35

36
        if (Log.Instance.IsTraceEnabled)
37
            Log.Instance.Trace($"Applying state...");
38

39
        var (presetId, preset) = await GetActivePresetAsync().ConfigureAwait(false);
40

41
        var settings = new Dictionary<CapabilityID, StepperValue?>
42
        {
43
            { CapabilityID.CPULongTermPowerLimit, preset.CPULongTermPowerLimit },
44
            { CapabilityID.CPUShortTermPowerLimit, preset.CPUShortTermPowerLimit },
45
            { CapabilityID.CPUPeakPowerLimit, preset.CPUPeakPowerLimit },
46
            { CapabilityID.CPUCrossLoadingPowerLimit, preset.CPUCrossLoadingPowerLimit },
47
            { CapabilityID.CPUPL1Tau, preset.CPUPL1Tau },
48
            { CapabilityID.APUsPPTPowerLimit, preset.APUsPPTPowerLimit },
49
            { CapabilityID.CPUTemperatureLimit, preset.CPUTemperatureLimit },
50
            { CapabilityID.GPUPowerBoost, preset.GPUPowerBoost },
51
            { CapabilityID.GPUConfigurableTGP, preset.GPUConfigurableTGP },
52
            { CapabilityID.GPUTemperatureLimit, preset.GPUTemperatureLimit },
53
            { CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline, preset.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline },
54
            { CapabilityID.GPUToCPUDynamicBoost, preset.GPUToCPUDynamicBoost },
55
        };
56

57
        var fanTable = preset.FanTable ?? await GetDefaultFanTableAsync().ConfigureAwait(false);
58
        var fanFullSpeed = preset.FanFullSpeed ?? false;
59

60
        foreach (var (id, value) in settings)
61
        {
62
            if (!value.HasValue)
63
                continue;
64

65
            try
66
            {
67
                if (Log.Instance.IsTraceEnabled)
68
                    Log.Instance.Trace($"Applying {id}: {value}...");
69

70
                await SetValueAsync(id, value.Value).ConfigureAwait(false);
71
            }
72
            catch (Exception ex)
73
            {
74
                if (Log.Instance.IsTraceEnabled)
75
                    Log.Instance.Trace($"Failed to apply {id}. [value={value}]", ex);
76
                throw;
77
            }
78
        }
79

80
        if (fanFullSpeed)
81
        {
82
            try
83
            {
84
                if (Log.Instance.IsTraceEnabled)
85
                    Log.Instance.Trace($"Applying Fan Full Speed {fanFullSpeed}...");
86

87
                await SetFanFullSpeedAsync(fanFullSpeed).ConfigureAwait(false);
88
            }
89
            catch (Exception ex)
90
            {
91
                if (Log.Instance.IsTraceEnabled)
92
                    Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
93
                throw;
94
            }
95
        }
96
        else
97
        {
98
            try
99
            {
100
                if (Log.Instance.IsTraceEnabled)
101
                    Log.Instance.Trace($"Making sure Fan Full Speed is false...");
102

103
                await SetFanFullSpeedAsync(false).ConfigureAwait(false);
104
            }
105
            catch (Exception ex)
106
            {
107
                if (Log.Instance.IsTraceEnabled)
108
                    Log.Instance.Trace($"Apply failed. [setting=fanFullSpeed]", ex);
109
                throw;
110
            }
111

112
            try
113
            {
114
                if (Log.Instance.IsTraceEnabled)
115
                    Log.Instance.Trace($"Applying Fan Table {fanTable}...");
116

117
                if (!await IsValidFanTableAsync(fanTable).ConfigureAwait(false))
118
                {
119
                    if (Log.Instance.IsTraceEnabled)
120
                        Log.Instance.Trace($"Fan table invalid, replacing with default...");
121

122
                    fanTable = await GetDefaultFanTableAsync().ConfigureAwait(false);
123
                }
124

125
                await SetFanTable(fanTable).ConfigureAwait(false);
126
            }
127
            catch (Exception ex)
128
            {
129
                if (Log.Instance.IsTraceEnabled)
130
                    Log.Instance.Trace($"Apply failed. [setting=fanTable]", ex);
131
                throw;
132
            }
133
        }
134

135
        RaisePresetChanged(presetId);
136

137
        if (Log.Instance.IsTraceEnabled)
138
            Log.Instance.Trace($"State applied. [name={preset.Name}, id={presetId}]");
139
    }
140

141
    public override Task<FanTable> GetMinimumFanTableAsync()
142
    {
143
        var fanTable = new FanTable(new ushort[] { 1, 1, 1, 1, 1, 1, 1, 1, 3, 5 });
144
        return Task.FromResult(fanTable);
145
    }
146

147
    public override async Task<Dictionary<PowerModeState, GodModeDefaults>> GetDefaultsInOtherPowerModesAsync()
148
    {
149
        try
150
        {
151
            if (Log.Instance.IsTraceEnabled)
152
                Log.Instance.Trace($"Getting defaults in other power modes...");
153

154
            var result = new Dictionary<PowerModeState, GodModeDefaults>();
155

156
            var allCapabilityData = await WMI.LenovoCapabilityData01.ReadAsync().ConfigureAwait(false);
157
            allCapabilityData = allCapabilityData.ToArray();
158

159
            foreach (var powerMode in new[] { PowerModeState.Quiet, PowerModeState.Balance, PowerModeState.Performance })
160
            {
161
                var defaults = new GodModeDefaults
162
                {
163
                    CPULongTermPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPULongTermPowerLimit, powerMode),
164
                    CPUShortTermPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUShortTermPowerLimit, powerMode),
165
                    CPUPeakPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUPeakPowerLimit, powerMode),
166
                    CPUCrossLoadingPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUCrossLoadingPowerLimit, powerMode),
167
                    CPUPL1Tau = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUPL1Tau, powerMode),
168
                    APUsPPTPowerLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.APUsPPTPowerLimit, powerMode),
169
                    CPUTemperatureLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.CPUTemperatureLimit, powerMode),
170
                    GPUPowerBoost = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUPowerBoost, powerMode),
171
                    GPUConfigurableTGP = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUConfigurableTGP, powerMode),
172
                    GPUTemperatureLimit = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUTemperatureLimit, powerMode),
173
                    GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline, powerMode),
174
                    GPUToCPUDynamicBoost = GetDefaultCapabilityIdValueInPowerMode(allCapabilityData, CapabilityID.GPUToCPUDynamicBoost, powerMode),
175
                    FanTable = await GetDefaultFanTableAsync().ConfigureAwait(false),
176
                    FanFullSpeed = false
177
                };
178

179
                result[powerMode] = defaults;
180
            }
181

182
            if (Log.Instance.IsTraceEnabled)
183
            {
184
                Log.Instance.Trace($"Defaults in other power modes retrieved:");
185
                foreach (var (powerMode, defaults) in result)
186
                    Log.Instance.Trace($" - {powerMode}: {defaults}");
187
            }
188

189
            return result;
190
        }
191
        catch (Exception ex)
192
        {
193
            if (Log.Instance.IsTraceEnabled)
194
                Log.Instance.Trace($"Failed to get defaults in other power modes.", ex);
195

196
            return new Dictionary<PowerModeState, GodModeDefaults>();
197
        }
198
    }
199

200
    public override Task RestoreDefaultsInOtherPowerModeAsync(PowerModeState _) => Task.CompletedTask;
201

202
    protected override async Task<GodModePreset> GetDefaultStateAsync()
203
    {
204
        var allCapabilityData = await WMI.LenovoCapabilityData01.ReadAsync().ConfigureAwait(false);
205
        allCapabilityData = allCapabilityData.ToArray();
206

207
        var capabilityData = allCapabilityData
208
            .Where(d => Enum.IsDefined(d.Id))
209
            .ToArray();
210

211
        var allDiscreteData = await WMI.LenovoDiscreteData.ReadAsync().ConfigureAwait(false);
212
        allDiscreteData = allDiscreteData.ToArray();
213

214
        var discreteData = allDiscreteData
215
            .Where(d => Enum.IsDefined(d.Id))
216
            .GroupBy(d => d.Id, d => d.Value, (id, values) => (id, values))
217
            .ToDictionary(d => d.id, d => d.values.ToArray());
218

219
        var stepperValues = new Dictionary<CapabilityID, StepperValue>();
220

221
        foreach (var c in capabilityData)
222
        {
223
            var value = await GetValueAsync(c.Id).OrNullIfException().ConfigureAwait(false) ?? c.DefaultValue;
224
            var steps = discreteData.GetValueOrDefault(c.Id) ?? Array.Empty<int>();
225

226
            if (c.Step == 0 && steps.Length < 1)
227
                continue;
228

229
            if (Log.Instance.IsTraceEnabled)
230
                Log.Instance.Trace($"Creating StepperValue {c.Id}... [idRaw={(int)c.Id:X}, defaultValue={c.DefaultValue}, min={c.Min}, max={c.Max}, step={c.Step}, steps={string.Join(", ", steps)}]");
231

232
            var stepperValue = new StepperValue(value, c.Min, c.Max, c.Step, steps, c.DefaultValue);
233
            stepperValues[c.Id] = stepperValue;
234
        }
235

236
        var fanTableData = await GetFanTableDataAsync().ConfigureAwait(false);
237

238
        var preset = new GodModePreset
239
        {
240
            Name = "Default",
241
            CPULongTermPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPULongTermPowerLimit),
242
            CPUShortTermPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUShortTermPowerLimit),
243
            CPUPeakPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUPeakPowerLimit),
244
            CPUCrossLoadingPowerLimit = stepperValues.GetValueOrNull(CapabilityID.CPUCrossLoadingPowerLimit),
245
            CPUPL1Tau = stepperValues.GetValueOrNull(CapabilityID.CPUPL1Tau),
246
            APUsPPTPowerLimit = stepperValues.GetValueOrNull(CapabilityID.APUsPPTPowerLimit),
247
            CPUTemperatureLimit = stepperValues.GetValueOrNull(CapabilityID.CPUTemperatureLimit),
248
            GPUPowerBoost = stepperValues.GetValueOrNull(CapabilityID.GPUPowerBoost),
249
            GPUConfigurableTGP = stepperValues.GetValueOrNull(CapabilityID.GPUConfigurableTGP),
250
            GPUTemperatureLimit = stepperValues.GetValueOrNull(CapabilityID.GPUTemperatureLimit),
251
            GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline = stepperValues.GetValueOrNull(CapabilityID.GPUTotalProcessingPowerTargetOnAcOffsetFromBaseline),
252
            GPUToCPUDynamicBoost = stepperValues.GetValueOrNull(CapabilityID.GPUToCPUDynamicBoost),
253
            FanTableInfo = fanTableData is null ? null : new FanTableInfo(fanTableData, await GetDefaultFanTableAsync().ConfigureAwait(false)),
254
            FanFullSpeed = await GetFanFullSpeedAsync().ConfigureAwait(false),
255
            MinValueOffset = 0,
256
            MaxValueOffset = 0
257
        };
258

259
        if (Log.Instance.IsTraceEnabled)
260
            Log.Instance.Trace($"Default state retrieved: {preset}");
261

262
        return preset;
263
    }
264

265
    private static CapabilityID AdjustCapabilityIdForPowerMode(CapabilityID id, PowerModeState powerMode)
266
    {
267
        var idRaw = (uint)id & 0xFFFF00FF;
268
        var powerModeRaw = ((uint)powerMode + 1) << 8;
269
        return (CapabilityID)(idRaw + powerModeRaw);
270
    }
271

272
    private static int? GetDefaultCapabilityIdValueInPowerMode(IEnumerable<RangeCapability> capabilities, CapabilityID id, PowerModeState powerMode)
273
    {
274
        var adjustedId = AdjustCapabilityIdForPowerMode(id, powerMode);
275
        var value = capabilities
276
            .Where(c => c.Id == adjustedId)
277
            .Select(c => c.DefaultValue)
278
            .DefaultIfEmpty(-1)
279
            .First();
280
        return value < 0 ? null : value;
281
    }
282

283
    #region Get/Set Value
284

285
    private static Task<int> GetValueAsync(CapabilityID id)
286
    {
287
        var idRaw = (uint)id & 0xFFFF00FF;
288
        return WMI.LenovoOtherMethod.GetFeatureValueAsync(idRaw);
289
    }
290

291
    private static Task SetValueAsync(CapabilityID id, StepperValue value)
292
    {
293
        var idRaw = (uint)id & 0xFFFF00FF;
294
        return WMI.LenovoOtherMethod.SetFeatureValueAsync(idRaw, value.Value);
295
    }
296

297
    #endregion
298

299
    #region Fan Table
300

301
    private static async Task<FanTableData[]?> GetFanTableDataAsync(PowerModeState powerModeState = PowerModeState.GodMode)
302
    {
303
        if (Log.Instance.IsTraceEnabled)
304
            Log.Instance.Trace($"Reading fan table data...");
305

306
        var data = await WMI.LenovoFanTableData.ReadAsync().ConfigureAwait(false);
307

308
        var fanTableData = data
309
            .Where(d => d.mode == (int)powerModeState + 1)
310
            .Select(d => new FanTableData
311
            {
312
                Type = (d.fanId, d.sensorId) switch
313
                {
314
                    (1, 4) => FanTableType.CPU,
315
                    (1, 1) => FanTableType.CPUSensor,
316
                    (2, 5) => FanTableType.GPU,
317
                    _ => FanTableType.Unknown,
318
                },
319
                FanId = d.fanId,
320
                SensorId = d.sensorId,
321
                FanSpeeds = d.fanTableData,
322
                Temps = d.sensorTableData
323
            })
324
            .ToArray();
325

326
        if (fanTableData.Length != 3)
327
        {
328
            if (Log.Instance.IsTraceEnabled)
329
                Log.Instance.Trace($"Bad fan table length: {string.Join(", ", fanTableData)}");
330

331
            return null;
332
        }
333

334
        if (fanTableData.Count(ftd => ftd.FanSpeeds.Length == 10) != 3)
335
        {
336
            if (Log.Instance.IsTraceEnabled)
337
                Log.Instance.Trace($"Bad fan table fan speeds length: {string.Join(", ", fanTableData)}");
338

339
            return null;
340
        }
341

342
        if (fanTableData.Count(ftd => ftd.Temps.Length == 10) != 3)
343
        {
344
            if (Log.Instance.IsTraceEnabled)
345
                Log.Instance.Trace($"Bad fan table temps length: {string.Join(", ", fanTableData)}");
346

347
            return null;
348
        }
349

350
        if (Log.Instance.IsTraceEnabled)
351
            Log.Instance.Trace($"Fan table data: {string.Join(", ", fanTableData)}");
352

353
        return fanTableData;
354
    }
355

356
    private static Task SetFanTable(FanTable fanTable) => WMI.LenovoFanMethod.FanSetTableAsync(fanTable.GetBytes());
357

358
    #endregion
359

360
    #region Fan Full Speed
361

362
    private static async Task<bool> GetFanFullSpeedAsync()
363
    {
364
        var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.FanFullSpeed).ConfigureAwait(false);
365
        return value != 0;
366
    }
367

368
    private static Task SetFanFullSpeedAsync(bool enabled) => WMI.LenovoOtherMethod.SetFeatureValueAsync(CapabilityID.FanFullSpeed, enabled ? 1 : 0);
369

370
    #endregion
371

372
}
373

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.