mirror of
https://github.com/openhardwaremonitor/openhardwaremonitor
synced 2025-08-30 05:47:38 +00:00
Changed the SMART AttributeID type from an enum to a struct.
This commit is contained in:
parent
edec08400d
commit
f34f8c996c
@ -49,36 +49,31 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
private readonly int drive;
|
private readonly int drive;
|
||||||
private int count;
|
private int count;
|
||||||
|
|
||||||
private readonly SMART.AttributeID temperatureID = 0x00;
|
private readonly SMART.AttributeID temperatureID = SMART.AttributeID.None;
|
||||||
private readonly SMART.SSDLifeID lifeID = 0x00;
|
private readonly SMART.AttributeID lifeID = SMART.AttributeID.None;
|
||||||
|
|
||||||
private readonly Sensor temperatureSensor;
|
private readonly Sensor temperatureSensor;
|
||||||
private readonly Sensor lifeSensor;
|
private readonly Sensor lifeSensor;
|
||||||
|
|
||||||
public HDD(string name, IntPtr handle, int drive,
|
public HDD(string name, IntPtr handle, int drive,
|
||||||
SMART.AttributeID temperatureID, ISettings settings)
|
SMART.AttributeID temperatureID, SMART.AttributeID lifeID,
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
this.handle = handle;
|
|
||||||
this.drive = drive;
|
|
||||||
this.count = 0;
|
|
||||||
this.temperatureID = temperatureID;
|
|
||||||
this.temperatureSensor = new Sensor("HDD", 0, SensorType.Temperature,
|
|
||||||
this, settings);
|
|
||||||
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HDD(string name, IntPtr handle, int drive, SMART.SSDLifeID lifeID,
|
|
||||||
ISettings settings)
|
ISettings settings)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.drive = drive;
|
this.drive = drive;
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.lifeID = lifeID;
|
if (temperatureID != SMART.AttributeID.None) {
|
||||||
this.lifeSensor = new Sensor("Remaining life", 0, SensorType.Level,
|
this.temperatureID = temperatureID;
|
||||||
this, settings);
|
this.temperatureSensor = new Sensor("HDD", 0, SensorType.Temperature,
|
||||||
|
this, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lifeID != SMART.AttributeID.None) {
|
||||||
|
this.lifeID = lifeID;
|
||||||
|
this.lifeSensor = new Sensor("Remaining life", 0, SensorType.Level,
|
||||||
|
this, settings);
|
||||||
|
}
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -108,10 +103,10 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
|
|
||||||
public ISensor[] Sensors {
|
public ISensor[] Sensors {
|
||||||
get {
|
get {
|
||||||
if (lifeID != SMART.SSDLifeID.None)
|
if (lifeID != SMART.AttributeID.None)
|
||||||
return new ISensor[] { lifeSensor };
|
return new ISensor[] { lifeSensor };
|
||||||
|
|
||||||
if (temperatureID != 0x00)
|
if (temperatureID != SMART.AttributeID.None)
|
||||||
return new ISensor[] { temperatureSensor };
|
return new ISensor[] { temperatureSensor };
|
||||||
|
|
||||||
return new ISensor[] {};
|
return new ISensor[] {};
|
||||||
@ -125,27 +120,27 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
public void Update() {
|
public void Update() {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
|
List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
|
||||||
if (temperatureID != 0x00 &&
|
if (temperatureID != SMART.AttributeID.None &&
|
||||||
attributes.Exists(attr => (int)attr.ID == (int)temperatureID))
|
attributes.Exists(attr => attr.ID == temperatureID))
|
||||||
{
|
{
|
||||||
temperatureSensor.Value = attributes
|
temperatureSensor.Value = attributes
|
||||||
.Find(attr => (int)attr.ID == (int)temperatureID)
|
.Find(attr => attr.ID == temperatureID)
|
||||||
.RawValue[0];
|
.RawValue[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lifeID != 0x00 &&
|
if (lifeID != SMART.AttributeID.None &&
|
||||||
attributes.Exists(attr => (int)attr.ID == (int)lifeID))
|
attributes.Exists(attr => attr.ID == lifeID))
|
||||||
{
|
{
|
||||||
lifeSensor.Value = attributes
|
lifeSensor.Value = attributes
|
||||||
.Find(attr => (int)attr.ID == (int)lifeID)
|
.Find(attr => attr.ID == lifeID)
|
||||||
.AttrValue;
|
.AttrValue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (temperatureID != 0x00) {
|
if (temperatureID != SMART.AttributeID.None) {
|
||||||
temperatureSensor.Value = temperatureSensor.Value;
|
temperatureSensor.Value = temperatureSensor.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lifeID != 0x00) {
|
if (lifeID != SMART.AttributeID.None) {
|
||||||
lifeSensor.Value = lifeSensor.Value;
|
lifeSensor.Value = lifeSensor.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,16 +76,18 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMART.SSDLifeID ssdLifeID = GetSSDLifeID(attributes);
|
SMART.AttributeID ssdLifeID = GetSSDLifeID(attributes);
|
||||||
if (ssdLifeID == SMART.SSDLifeID.None) {
|
if (ssdLifeID == SMART.AttributeID.None) {
|
||||||
SMART.AttributeID temperatureID = GetTemperatureIndex(attributes);
|
SMART.AttributeID temperatureID = GetTemperatureIndex(attributes);
|
||||||
|
|
||||||
if (temperatureID != 0x00) {
|
if (temperatureID != SMART.AttributeID.None) {
|
||||||
hardware.Add(new HDD(name, handle, drive, temperatureID, settings));
|
hardware.Add(new HDD(name, handle, drive, temperatureID,
|
||||||
|
SMART.AttributeID.None, settings));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hardware.Add(new HDD(name, handle, drive, ssdLifeID, settings));
|
hardware.Add(new HDD(name, handle, drive, SMART.AttributeID.None,
|
||||||
|
ssdLifeID, settings));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,29 +95,28 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SMART.SSDLifeID GetSSDLifeID(List<SMART.DriveAttribute> attributes) {
|
private SMART.AttributeID GetSSDLifeID(List<SMART.DriveAttribute> attributes) {
|
||||||
// ID E9 is present on Intel, JM, SF and Samsung
|
// ID E9 is present on Intel, JM, SF and Samsung
|
||||||
// ID D2 is present on Indilinx
|
// ID D2 is present on Indilinx
|
||||||
// Neither ID has been found on a mechanical hard drive (yet),
|
// Neither ID has been found on a mechanical hard drive (yet),
|
||||||
// So this seems like a good way to check if it's an SSD.
|
// So this seems like a good way to check if it's an SSD.
|
||||||
bool isKnownSSD = (attributes.Exists(attr => (int)attr.ID == 0xE9) ||
|
bool isKnownSSD = (
|
||||||
attributes.Exists(attr => (int)attr.ID == 0xD2)
|
attributes.Exists(attr => attr.ID == new SMART.AttributeID(0xE9)) ||
|
||||||
|
attributes.Exists(attr => attr.ID == new SMART.AttributeID(0xD2))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isKnownSSD) return SMART.SSDLifeID.None;
|
if (!isKnownSSD) return SMART.AttributeID.None;
|
||||||
|
|
||||||
// We start with a traditional loop, because there are 4 unique ID's
|
// We start with a traditional loop, because there are 4 unique ID's
|
||||||
// that potentially identify one of the vendors
|
// that potentially identify one of the vendors
|
||||||
for (int i = 0; i < attributes.Count; i++) {
|
for (int i = 0; i < attributes.Count; i++) {
|
||||||
|
|
||||||
switch ((int)attributes[i].ID) {
|
if (attributes[i].ID == SMART.SamsungAttributes.RemainingLife)
|
||||||
case 0xB4:
|
return SMART.SamsungAttributes.RemainingLife;
|
||||||
return SMART.SSDLifeID.Samsung;
|
else if (attributes[i].ID == new SMART.AttributeID(0xAB))
|
||||||
case 0xAB:
|
return SMART.SandForceAttributes.RemainingLife;
|
||||||
return SMART.SSDLifeID.SandForce;
|
else if (attributes[i].ID == new SMART.AttributeID(0xD2))
|
||||||
case 0xD2:
|
return SMART.IndilinxAttributes.RemainingLife;
|
||||||
return SMART.SSDLifeID.Indilinx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4
|
// TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4
|
||||||
@ -125,25 +126,25 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
// is whether we can find all 3; pointless to use Exists()
|
// is whether we can find all 3; pointless to use Exists()
|
||||||
int intelRegisterCount = 0;
|
int intelRegisterCount = 0;
|
||||||
foreach (SMART.DriveAttribute attribute in attributes) {
|
foreach (SMART.DriveAttribute attribute in attributes) {
|
||||||
if ((int)attribute.ID == 0xE1 ||
|
if (attribute.ID == new SMART.AttributeID(0xE1) ||
|
||||||
(int)attribute.ID == 0xE8 ||
|
attribute.ID == new SMART.AttributeID(0xE8) ||
|
||||||
(int)attribute.ID == 0xE9
|
attribute.ID == new SMART.AttributeID(0xE9)
|
||||||
)
|
)
|
||||||
intelRegisterCount++;
|
intelRegisterCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (intelRegisterCount == 3)
|
return (intelRegisterCount == 3)
|
||||||
? SMART.SSDLifeID.Intel
|
? SMART.IntelAttributes.RemainingLife
|
||||||
: SMART.SSDLifeID.None;
|
: SMART.AttributeID.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SMART.AttributeID GetTemperatureIndex(
|
private SMART.AttributeID GetTemperatureIndex(
|
||||||
List<SMART.DriveAttribute> attributes)
|
List<SMART.DriveAttribute> attributes)
|
||||||
{
|
{
|
||||||
SMART.AttributeID[] validIds = new[] {
|
SMART.AttributeID[] validIds = new[] {
|
||||||
SMART.AttributeID.Temperature,
|
SMART.CommonAttributes.Temperature,
|
||||||
SMART.AttributeID.DriveTemperature,
|
SMART.CommonAttributes.DriveTemperature,
|
||||||
SMART.AttributeID.AirflowTemperature
|
SMART.CommonAttributes.AirflowTemperature
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (SMART.AttributeID validId in validIds) {
|
foreach (SMART.AttributeID validId in validIds) {
|
||||||
@ -152,7 +153,7 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
return validId;
|
return validId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x00;
|
return SMART.AttributeID.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IHardware[] Hardware {
|
public IHardware[] Hardware {
|
||||||
@ -201,7 +202,7 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
Environment.NewLine);
|
Environment.NewLine);
|
||||||
|
|
||||||
foreach (SMART.DriveAttribute a in attributes) {
|
foreach (SMART.DriveAttribute a in attributes) {
|
||||||
if (a.ID == 0) continue;
|
if (a.ID == SMART.AttributeID.None) continue;
|
||||||
string raw = BitConverter.ToString(a.RawValue);
|
string raw = BitConverter.ToString(a.RawValue);
|
||||||
r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
|
r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
|
||||||
a.ID.ToString("d").PadRight(6),
|
a.ID.ToString("d").PadRight(6),
|
||||||
|
@ -53,37 +53,100 @@ namespace OpenHardwareMonitor.Hardware.HDD {
|
|||||||
SelfPreserving = 0x20
|
SelfPreserving = 0x20
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AttributeID : byte {
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
ReadErrorRate = 0x01,
|
public struct AttributeID {
|
||||||
ThroughputPerformance = 0x02,
|
private byte value;
|
||||||
SpinUpTime = 0x03,
|
|
||||||
StartStopCount = 0x04,
|
public AttributeID(byte value) {
|
||||||
ReallocatedSectorsCount = 0x05,
|
this.value = value;
|
||||||
ReadChannelMargin = 0x06,
|
}
|
||||||
SeekErrorRate = 0x07,
|
|
||||||
SeekTimePerformance = 0x08,
|
public override bool Equals(Object obj) {
|
||||||
PowerOnHours = 0x09,
|
return obj is AttributeID && this == (AttributeID)obj;
|
||||||
SpinRetryCount = 0x0A,
|
}
|
||||||
RecalibrationRetries = 0x0B,
|
public override int GetHashCode() {
|
||||||
PowerCycleCount = 0x0C,
|
return value.GetHashCode() ^ value.GetHashCode();
|
||||||
SoftReadErrorRate = 0x0D,
|
}
|
||||||
AirflowTemperature = 0xBE,
|
public static bool operator ==(AttributeID a, AttributeID b) {
|
||||||
Temperature = 0xC2,
|
return a.value == b.value;
|
||||||
HardwareECCRecovered = 0xC3,
|
}
|
||||||
ReallocationEventCount = 0xC4,
|
public static bool operator !=(AttributeID a, AttributeID b) {
|
||||||
CurrentPendingSectorCount = 0xC5,
|
return !(a == b);
|
||||||
UncorrectableSectorCount = 0xC6,
|
}
|
||||||
UltraDMACRCErrorCount = 0xC7,
|
|
||||||
WriteErrorRate = 0xC8,
|
public string ToString(string format) {
|
||||||
DriveTemperature = 0xE7
|
return value.ToString(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly AttributeID None = new AttributeID(0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SSDLifeID {
|
// Common SMART attributes
|
||||||
None = 0x00,
|
public static class CommonAttributes {
|
||||||
Indilinx = 0xD1,
|
public static readonly AttributeID
|
||||||
Intel = 0xE8,
|
ReadErrorRate = new AttributeID(0x01);
|
||||||
Samsung = 0xB4,
|
public static readonly AttributeID
|
||||||
SandForce = 0xE7
|
ThroughputPerformance = new AttributeID(0x02);
|
||||||
|
public static readonly AttributeID
|
||||||
|
SpinUpTime = new AttributeID(0x03);
|
||||||
|
public static readonly AttributeID
|
||||||
|
StartStopCount = new AttributeID(0x04);
|
||||||
|
public static readonly AttributeID
|
||||||
|
ReallocatedSectorsCount = new AttributeID(0x05);
|
||||||
|
public static readonly AttributeID
|
||||||
|
ReadChannelMargin = new AttributeID(0x06);
|
||||||
|
public static readonly AttributeID
|
||||||
|
SeekErrorRate = new AttributeID(0x07);
|
||||||
|
public static readonly AttributeID
|
||||||
|
SeekTimePerformance = new AttributeID(0x08);
|
||||||
|
public static readonly AttributeID
|
||||||
|
PowerOnHours = new AttributeID(0x09);
|
||||||
|
public static readonly AttributeID
|
||||||
|
SpinRetryCount = new AttributeID(0x0A);
|
||||||
|
public static readonly AttributeID
|
||||||
|
RecalibrationRetries = new AttributeID(0x0B);
|
||||||
|
public static readonly AttributeID
|
||||||
|
PowerCycleCount = new AttributeID(0x0C);
|
||||||
|
public static readonly AttributeID
|
||||||
|
SoftReadErrorRate = new AttributeID(0x0D);
|
||||||
|
public static readonly AttributeID
|
||||||
|
AirflowTemperature = new AttributeID(0xBE);
|
||||||
|
public static readonly AttributeID
|
||||||
|
Temperature = new AttributeID(0xC2);
|
||||||
|
public static readonly AttributeID
|
||||||
|
HardwareECCRecovered = new AttributeID(0xC3);
|
||||||
|
public static readonly AttributeID
|
||||||
|
ReallocationEventCount = new AttributeID(0xC4);
|
||||||
|
public static readonly AttributeID
|
||||||
|
CurrentPendingSectorCount = new AttributeID(0xC5);
|
||||||
|
public static readonly AttributeID
|
||||||
|
UncorrectableSectorCount = new AttributeID(0xC6);
|
||||||
|
public static readonly AttributeID
|
||||||
|
UltraDMACRCErrorCount = new AttributeID(0xC7);
|
||||||
|
public static readonly AttributeID
|
||||||
|
WriteErrorRate = new AttributeID(0xC8);
|
||||||
|
public static readonly AttributeID
|
||||||
|
DriveTemperature = new AttributeID(0xE7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indilinx SSD SMART attributes
|
||||||
|
public static class IndilinxAttributes {
|
||||||
|
public static readonly AttributeID RemainingLife = new AttributeID(0xD1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intel SSD SMART attributes
|
||||||
|
public static class IntelAttributes {
|
||||||
|
public static readonly AttributeID RemainingLife = new AttributeID(0xE8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samsung SSD SMART attributes
|
||||||
|
public static class SamsungAttributes {
|
||||||
|
public static readonly AttributeID RemainingLife = new AttributeID(0xB4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SandForce SSD SMART attributes
|
||||||
|
public static class SandForceAttributes {
|
||||||
|
public static readonly AttributeID RemainingLife = new AttributeID(0xE7);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user