Changed the SMART AttributeID type from an enum to a struct.

This commit is contained in:
Michael Möller 2010-10-17 17:12:38 +00:00
parent edec08400d
commit f34f8c996c
3 changed files with 145 additions and 86 deletions

View File

@ -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;
} }
} }

View File

@ -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),

View File

@ -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)]