diff --git a/LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV2.cs b/LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV2.cs index e577a6c321..c06bc5dd0d 100644 --- a/LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV2.cs +++ b/LenovoLegionToolkit.Lib/Controllers/GodMode/GodModeControllerV2.cs @@ -366,17 +366,21 @@ private static Task SetValueAsync(CapabilityID id, int value) Log.Instance.Trace($"Reading fan table data..."); var data = await WMI.LenovoFanTableData.ReadAsync().ConfigureAwait(false); + var mi = await Compatibility.GetMachineInformationAsync().ConfigureAwait(false); var fanTableData = data .Where(d => d.mode == (int)powerModeState + 1) .Select(d => { - var type = (d.fanId, d.sensorId) switch + var type = (d.fanId, d.sensorId, mi.SmartFanVersion) switch { - (1, 4) => FanTableType.CPU, - (1, 1) => FanTableType.CPUSensor, - (2, 5) => FanTableType.GPU, - (3, 5) => FanTableType.GPU2, + (1, 1, 8) => FanTableType.CPU, + (2, 5, 8) => FanTableType.GPU, + (4, 4, 8) => FanTableType.GPU2, + (1, 4, <= 8) => FanTableType.CPU, + (1, 1, <= 8) => FanTableType.CPUSensor, + (2, 5, <= 8) => FanTableType.GPU, + (3, 5, <= 8) => FanTableType.GPU2, _ => FanTableType.Unknown, }; return new FanTableData(type, d.fanId, d.sensorId, d.fanTableData, d.sensorTableData); diff --git a/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsController.cs b/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsController.cs index d5d6df25a6..f3a52a7ffc 100644 --- a/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsController.cs +++ b/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsController.cs @@ -6,7 +6,8 @@ namespace LenovoLegionToolkit.Lib.Controllers.Sensors; public class SensorsController( SensorsControllerV1 controllerV1, SensorsControllerV2 controllerV2, - SensorsControllerV3 controllerV3) + SensorsControllerV3 controllerV3, + SensorsControllerV4 controllerV4) : ISensorsController { private ISensorsController? _controller; @@ -36,6 +37,9 @@ public async Task GetDataAsync() if (_controller is not null) return _controller; + if (await controllerV4.IsSupportedAsync().ConfigureAwait(false)) + return _controller = controllerV4; + if (await controllerV3.IsSupportedAsync().ConfigureAwait(false)) return _controller = controllerV3; diff --git a/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV4.cs b/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV4.cs new file mode 100644 index 0000000000..0fc742fcf6 --- /dev/null +++ b/LenovoLegionToolkit.Lib/Controllers/Sensors/SensorsControllerV4.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using LenovoLegionToolkit.Lib.System.Management; +using LenovoLegionToolkit.Lib.Utils; + +namespace LenovoLegionToolkit.Lib.Controllers.Sensors; + +public class SensorsControllerV4(GPUController gpuController) : AbstractSensorsController(gpuController) +{ + private const int CPU_SENSOR_ID = 1; + private const int GPU_SENSOR_ID = 5; + private const int CPU_FAN_ID = 1; + private const int GPU_FAN_ID = 2; + + public override async Task IsSupportedAsync() + { + try + { + var result = await WMI.LenovoFanTableData.ExistsAsync(CPU_SENSOR_ID, CPU_FAN_ID).ConfigureAwait(false); + result &= await WMI.LenovoFanTableData.ExistsAsync(GPU_SENSOR_ID, GPU_FAN_ID).ConfigureAwait(false); + + if (result) + _ = await GetDataAsync().ConfigureAwait(false); + + return result; + } + catch (Exception ex) + { + if (Log.Instance.IsTraceEnabled) + Log.Instance.Trace($"Error checking support. [type={GetType().Name}]", ex); + + return false; + } + } + + protected override async Task GetCpuCurrentTemperatureAsync() + { + var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.CpuCurrentTemperature).ConfigureAwait(false); + return value < 1 ? -1 : value; + } + + protected override async Task GetGpuCurrentTemperatureAsync() + { + var value = await WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.GpuCurrentTemperature).ConfigureAwait(false); + return value < 1 ? -1 : value; + } + + protected override Task GetCpuCurrentFanSpeedAsync() => WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.CpuCurrentFanSpeed); + + protected override Task GetGpuCurrentFanSpeedAsync() => WMI.LenovoOtherMethod.GetFeatureValueAsync(CapabilityID.GpuCurrentFanSpeed); + + protected override Task GetCpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(CPU_SENSOR_ID, CPU_FAN_ID); + + protected override Task GetGpuMaxFanSpeedAsync() => WMI.LenovoFanMethod.GetCurrentFanMaxSpeedAsync(GPU_SENSOR_ID, GPU_FAN_ID); +} diff --git a/LenovoLegionToolkit.Lib/IoCModule.cs b/LenovoLegionToolkit.Lib/IoCModule.cs index e3987708de..133ee85a9e 100644 --- a/LenovoLegionToolkit.Lib/IoCModule.cs +++ b/LenovoLegionToolkit.Lib/IoCModule.cs @@ -117,6 +117,7 @@ protected override void Load(ContainerBuilder builder) builder.Register(true); builder.Register(true); builder.Register(true); + builder.Register(true); builder.Register(); builder.Register(); builder.Register(); diff --git a/LenovoLegionToolkit.Lib/System/Devices.cs b/LenovoLegionToolkit.Lib/System/Devices.cs index 518299bbd1..541e4fe4d5 100644 --- a/LenovoLegionToolkit.Lib/System/Devices.cs +++ b/LenovoLegionToolkit.Lib/System/Devices.cs @@ -261,6 +261,27 @@ public static unsafe SafeFileHandle GetBattery(bool forceRefresh = false) return _spectrumRgbKeyboard; } + public static SafeFileHandle? GetSpectrumRGBKeyboard2(bool forceRefresh = false) + { + if (_spectrumRgbKeyboard is not null && !forceRefresh) + return _spectrumRgbKeyboard; + + lock (Lock) + { + if (_spectrumRgbKeyboard is not null && !forceRefresh) + return _spectrumRgbKeyboard; + + const ushort vendorId = 0x048D; + const ushort productIdMasked = 0xC100; + const ushort productIdMask = 0xFF00; + const ushort descriptorLength = 0x03C0; + + _spectrumRgbKeyboard = FindHidDevice(vendorId, productIdMask, productIdMasked, descriptorLength); + } + + return _spectrumRgbKeyboard; + } + private static unsafe SafeFileHandle? FindHidDevice(ushort vendorId, ushort productIdMask, ushort productIdMasked, ushort descriptorLength) { PInvoke.HidD_GetHidGuid(out var devClassHidGuid); diff --git a/LenovoLegionToolkit.Lib/Utils/Compatibility.cs b/LenovoLegionToolkit.Lib/Utils/Compatibility.cs index 4d99f01160..0ab34c9c1b 100644 --- a/LenovoLegionToolkit.Lib/Utils/Compatibility.cs +++ b/LenovoLegionToolkit.Lib/Utils/Compatibility.cs @@ -323,7 +323,7 @@ private static bool GetSupportsGodModeV2(IEnumerable supportedPo if (!supportedPowerModes.Contains(PowerModeState.GodMode)) return false; - return smartFanVersion is 6 or 7 || legionZoneVersion is 3 or 4; + return smartFanVersion is 6 or 7 or 8 || legionZoneVersion is 3 or 4 or 5; } private static async Task GetSupportsGSyncAsync() diff --git a/LenovoLegionToolkit.SpectrumTester/Program.cs b/LenovoLegionToolkit.SpectrumTester/Program.cs index 87ccc3609c..90e3b3cc6a 100644 --- a/LenovoLegionToolkit.SpectrumTester/Program.cs +++ b/LenovoLegionToolkit.SpectrumTester/Program.cs @@ -13,7 +13,7 @@ 2. Set the keyboard brightness to maximum. "); Console.ReadKey(); -var device = Devices.GetSpectrumRGBKeyboard(); +var device = Devices.GetSpectrumRGBKeyboard2(); Console.WriteLine("Finding Spectrum keyboard..."); @@ -28,41 +28,95 @@ 2. Set the keyboard brightness to maximum. Console.WriteLine("Spectrum keyboard found"); Console.WriteLine(); -Console.WriteLine("Reading response for 0xD1..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownD1, 0, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resD1); -Print(resD1.Bytes); -Console.WriteLine(); +try +{ + Console.WriteLine("Reading response for 0xD1..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownD1, 0, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resD1); + Print(resD1.Bytes); -Console.WriteLine("Reading response for 0xC6..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC6, 0, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC6); -Print(resC6.Bytes); -Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(resD1.Bytes[4] == 0 ? "Keyboard is RGB." : "Not compatible."); + Console.WriteLine(); +} +catch +{ + Console.WriteLine("Reading 0xD1 failed."); +} -Console.WriteLine("Reading response for 0x04..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.Unknown04, 0, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE res04); -Print(res04.Bytes); -Console.WriteLine(); +try +{ + Console.WriteLine("Reading response for 0xC6..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC6, 0, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC6); + Print(resC6.Bytes); + Console.WriteLine(); +} +catch +{ + Console.WriteLine("Reading 0xC6 failed."); +} -Console.WriteLine("Reading response for 0xC7..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC7, 0, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC7); -Print(resC7.Bytes); -Console.WriteLine(); +try +{ + Console.WriteLine("Reading response for 0x04..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.Unknown04, 0, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE res04); + Print(res04.Bytes); + Console.WriteLine(); +} +catch +{ + Console.WriteLine("Reading 0x04 failed."); +} -Console.WriteLine("Reading response for 0xC4 7..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 7, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC47); -Print(resC47.Bytes); -Console.WriteLine(); +try +{ + Console.WriteLine("Reading response for 0xC7..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC7, 0, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC7); + Print(resC7.Bytes); + Console.WriteLine(); +} +catch +{ + Console.WriteLine("Reading 0xC7 failed."); +} -Console.WriteLine("Reading response for 0xC4 8..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 8, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC48); -Print(resC48.Bytes); -Console.WriteLine(); +try +{ + Console.WriteLine("Reading response for 0xC4 7..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 7, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC47); + Print(resC47.Bytes); + Console.WriteLine(); + + var spectrumLayout = (resC47.Bytes[6], resC47.Bytes[5]) switch + { + (22, 9) => "Full", + (20, 8) => "KeyboardAndFront", + (20, 7) => "KeyboardOnly", + _ => "Unknown" + }; + Console.WriteLine($"Layout is {spectrumLayout}."); +} +catch +{ + Console.WriteLine("Reading 0xC4 7 failed."); +} + +try +{ + Console.WriteLine("Reading response for 0xC4 8..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 8, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC48); + Print(resC48.Bytes); + Console.WriteLine(); +} +catch +{ + Console.WriteLine("Reading 0xC4 8 failed."); +} for (var i = 0; i < 10; i++) { @@ -73,22 +127,19 @@ 2. Set the keyboard brightness to maximum. Console.WriteLine(); } -Console.WriteLine($"Reading response for 0xC5 8..."); -SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC5, 8, 0)); -GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC58); -Print(resC58.Bytes); -Console.WriteLine(); - -Console.WriteLine(resD1.Bytes[4] == 0 ? "Keyboard is RGB." : "Not compatible."); - -var spectrumLayout = (resC47.Bytes[6], resC47.Bytes[5]) switch +try +{ + Console.WriteLine($"Reading response for 0xC5 8..."); + SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC5, 8, 0)); + GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC58); + Print(resC58.Bytes); + Console.WriteLine(); +} +catch { - (22, 9) => "Full", - (20, 8) => "KeyboardAndFront", - (20, 7) => "KeyboardOnly", - _ => "Unknown" -}; -Console.WriteLine($"Layout is {spectrumLayout}."); + Console.WriteLine("Reading 0xC5 8 failed."); +} + Console.WriteLine("Reading config complete."); Console.WriteLine(); Console.ReadKey();