Skip to content

Commit 5027bd9

Browse files
Add DIMM Temperature to LHM. (#1743)
* Add DIMM Temperature to LHM. * Remove RAMSPDToolkit as submodule and use nuget package instead. Upgrade System.Management assembly (required for nuget package). Implement retry mechanism for RAM detection due to possible issue at system boot. * Change to static field. * Driver now back in LHM. Ring0 replaced with OLS implementation. * Update package version. * Undo most of changes. Implement IDriver interface. * Change package to new one. * Review changes. Explicitly set UseWMI (current default is also false). * PR comments: Now having one DimmMemory instance per RAM stick. Separated memory sensors into two new classes. * PR feedback --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
1 parent 9cefa1c commit 5027bd9

13 files changed

Lines changed: 825 additions & 163 deletions
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
2+
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
3+
// Copyright (C) LibreHardwareMonitor and Contributors.
4+
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
5+
// All Rights Reserved.
6+
7+
using LibreHardwareMonitor.Hardware.Memory.Sensors;
8+
using RAMSPDToolkit.SPD;
9+
using RAMSPDToolkit.SPD.Enums;
10+
using RAMSPDToolkit.SPD.Interfaces;
11+
using RAMSPDToolkit.SPD.Interop.Shared;
12+
13+
namespace LibreHardwareMonitor.Hardware.Memory;
14+
15+
internal sealed class DimmMemory : Hardware
16+
{
17+
private readonly SpdThermalSensor _thermalSensor;
18+
19+
public DimmMemory(SPDAccessor accessor, string name, Identifier identifier, ISettings settings)
20+
: base(name, identifier, settings)
21+
{
22+
//Check which kind of RAM we have
23+
switch (accessor.MemoryType())
24+
{
25+
case SPDMemoryType.SPD_DDR4_SDRAM:
26+
case SPDMemoryType.SPD_DDR4E_SDRAM:
27+
case SPDMemoryType.SPD_LPDDR4_SDRAM:
28+
case SPDMemoryType.SPD_LPDDR4X_SDRAM:
29+
_thermalSensor = new SpdThermalSensor($"DIMM #{accessor.Index}",
30+
accessor.Index,
31+
SensorType.Temperature,
32+
this,
33+
settings,
34+
accessor as IThermalSensor);
35+
36+
break;
37+
case SPDMemoryType.SPD_DDR5_SDRAM:
38+
case SPDMemoryType.SPD_LPDDR5_SDRAM:
39+
//Check if we are on correct page or if write protection is not enabled
40+
if (accessor.PageData.HasFlag(PageData.ThermalData) || !accessor.HasSPDWriteProtection)
41+
{
42+
_thermalSensor = new SpdThermalSensor($"DIMM #{accessor.Index}",
43+
accessor.Index,
44+
SensorType.Temperature,
45+
this,
46+
settings,
47+
accessor as IThermalSensor);
48+
}
49+
50+
break;
51+
}
52+
53+
//Add thermal sensor
54+
if (_thermalSensor != null)
55+
ActivateSensor(_thermalSensor);
56+
}
57+
58+
public override HardwareType HardwareType => HardwareType.Memory;
59+
60+
public override void Update()
61+
{
62+
_thermalSensor?.UpdateSensor();
63+
}
64+
}

LibreHardwareMonitorLib/Hardware/Memory/GenericLinuxMemory.cs

Lines changed: 0 additions & 92 deletions
This file was deleted.

LibreHardwareMonitorLib/Hardware/Memory/GenericWindowsMemory.cs

Lines changed: 0 additions & 62 deletions
This file was deleted.

LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,137 @@
55
// All Rights Reserved.
66

77
using System.Collections.Generic;
8+
using System.Timers;
9+
using RAMSPDToolkit.I2CSMBus;
10+
using RAMSPDToolkit.SPD;
11+
using RAMSPDToolkit.SPD.Enums;
12+
using RAMSPDToolkit.SPD.Interfaces;
13+
using RAMSPDToolkit.SPD.Interop.Shared;
14+
using RAMSPDToolkit.Windows.Driver;
815

916
namespace LibreHardwareMonitor.Hardware.Memory;
1017

1118
internal class MemoryGroup : IGroup
1219
{
13-
private readonly Hardware[] _hardware;
20+
//Retry 12x
21+
private const int RetryCount = 12;
22+
23+
//Retry every 2.5 seconds
24+
private const double RetryTime = 2500;
25+
private static readonly object _lock = new();
26+
27+
private readonly List<Hardware> _hardware = [];
28+
private int _elapsedCounter;
29+
30+
private Timer _timer;
31+
32+
static MemoryGroup()
33+
{
34+
if (Ring0.IsOpen)
35+
{
36+
//Assign implementation of IDriver
37+
DriverManager.Driver = new RAMSPDToolkitDriver(Ring0.KernelDriver);
38+
SMBusManager.UseWMI = false;
39+
}
40+
}
1441

1542
public MemoryGroup(ISettings settings)
1643
{
17-
_hardware = new Hardware[] { Software.OperatingSystem.IsUnix ? new GenericLinuxMemory("Generic Memory", settings) : new GenericWindowsMemory("Generic Memory", settings) };
44+
_hardware.Add(new VirtualMemory(settings));
45+
_hardware.Add(new TotalMemory(settings));
46+
47+
//No RAM detected
48+
if (!DetectThermalSensors(out List<SPDAccessor> accessors))
49+
{
50+
//Retry a couple of times
51+
//SMBus might not be detected right after boot
52+
_timer = new Timer(RetryTime);
53+
54+
_timer.Elapsed += (_, _) =>
55+
{
56+
if (_elapsedCounter++ >= RetryCount || DetectThermalSensors(out accessors))
57+
{
58+
_timer.Stop();
59+
_timer = null;
60+
61+
if (accessors != null)
62+
AddDimms(accessors, settings);
63+
}
64+
};
65+
66+
_timer.Start();
67+
}
68+
else
69+
{
70+
AddDimms(accessors, settings);
71+
}
1872
}
1973

74+
public IReadOnlyList<IHardware> Hardware => _hardware;
75+
2076
public string GetReport()
2177
{
2278
return null;
2379
}
2480

25-
public IReadOnlyList<IHardware> Hardware => _hardware;
26-
2781
public void Close()
2882
{
2983
foreach (Hardware ram in _hardware)
3084
ram.Close();
3185
}
86+
87+
private static bool DetectThermalSensors(out List<SPDAccessor> accessors)
88+
{
89+
lock (_lock)
90+
{
91+
var list = new List<SPDAccessor>();
92+
93+
bool ramDetected = false;
94+
95+
SMBusManager.DetectSMBuses();
96+
97+
//Go through detected SMBuses
98+
foreach (var smbus in SMBusManager.RegisteredSMBuses)
99+
{
100+
//Go through possible RAM slots
101+
for (byte i = SPDConstants.SPD_BEGIN; i <= SPDConstants.SPD_END; ++i)
102+
{
103+
//Detect type of RAM, if available
104+
var detector = new SPDDetector(smbus, i);
105+
106+
//RAM available and detected
107+
if (detector.Accessor != null)
108+
{
109+
//We are only interested in modules with thermal sensor
110+
if (detector.Accessor is IThermalSensor { HasThermalSensor: true })
111+
list.Add(detector.Accessor);
112+
113+
ramDetected = true;
114+
}
115+
}
116+
}
117+
118+
accessors = list.Count > 0 ? list : [];
119+
return ramDetected;
120+
}
121+
}
122+
123+
private void AddDimms(List<SPDAccessor> accessors, ISettings settings)
124+
{
125+
foreach (var ram in accessors)
126+
{
127+
//Default value
128+
string name = $"DIMM #{ram.Index}";
129+
130+
//Check if we can switch to the correct page
131+
if (ram.ChangePage(PageData.ModulePartNumber))
132+
{
133+
name = $"{ram.GetModuleManufacturerString()} - {ram.ModulePartNumber()} (#{ram.Index})";
134+
}
135+
136+
var memory = new DimmMemory(ram, name, new Identifier("ram"), settings);
137+
138+
_hardware.Add(memory);
139+
}
140+
}
32141
}

0 commit comments

Comments
 (0)