moel@324: /* moel@324: moel@324: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@324: moel@324: The contents of this file are subject to the Mozilla Public License Version moel@324: 1.1 (the "License"); you may not use this file except in compliance with moel@324: the License. You may obtain a copy of the License at moel@324: moel@324: http://www.mozilla.org/MPL/ moel@324: moel@324: Software distributed under the License is distributed on an "AS IS" basis, moel@324: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@324: for the specific language governing rights and limitations under the License. moel@324: moel@324: The Original Code is the Open Hardware Monitor code. moel@324: moel@324: The Initial Developer of the Original Code is moel@324: Michael Möller . moel@325: Portions created by the Initial Developer are Copyright (C) 2009-2012 moel@324: the Initial Developer. All Rights Reserved. moel@324: moel@324: Contributor(s): moel@324: Paul Werelds moel@324: Roland Reinl moel@324: moel@324: Alternatively, the contents of this file may be used under the terms of moel@324: either the GNU General Public License Version 2 or later (the "GPL"), or moel@324: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@324: in which case the provisions of the GPL or the LGPL are applicable instead moel@324: of those above. If you wish to allow use of your version of this file only moel@324: under the terms of either the GPL or the LGPL, and not to allow others to moel@324: use your version of this file under the terms of the MPL, indicate your moel@324: decision by deleting the provisions above and replace them with the notice moel@324: and other provisions required by the GPL or the LGPL. If you do not delete moel@324: the provisions above, a recipient may use your version of this file under moel@324: the terms of any one of the MPL, the GPL or the LGPL. moel@324: moel@324: */ moel@324: moel@324: using System; moel@324: using System.Collections.Generic; moel@324: using System.Globalization; moel@324: using System.Text; moel@324: using OpenHardwareMonitor.Collections; moel@324: moel@324: namespace OpenHardwareMonitor.Hardware.HDD { moel@324: internal abstract class AbstractHarddrive : Hardware { moel@324: moel@324: private const int UPDATE_DIVIDER = 30; // update only every 30s moel@324: moel@324: // array of all harddrive types, matching type is searched in this order moel@324: private static Type[] hddTypes = { moel@324: typeof(SSDPlextor), moel@324: typeof(SSDIntel), moel@324: typeof(SSDSandforce), moel@324: typeof(SSDIndilinx), moel@328: typeof(SSDSamsung), moel@324: typeof(GenericHarddisk) moel@324: }; moel@324: moel@325: private string firmwareRevision; moel@324: private readonly ISmart smart; moel@324: moel@324: private readonly IntPtr handle; moel@324: private readonly int index; moel@324: private int count; moel@324: moel@324: private IList smartAttributes; moel@324: private IDictionary sensors; moel@324: moel@325: protected AbstractHarddrive(ISmart smart, string name, moel@325: string firmwareRevision, int index, moel@324: IEnumerable smartAttributes, ISettings settings) moel@324: : base(name, new Identifier("hdd", moel@324: index.ToString(CultureInfo.InvariantCulture)), settings) moel@324: { moel@325: this.firmwareRevision = firmwareRevision; moel@324: this.smart = smart; moel@324: handle = smart.OpenDrive(index); moel@324: moel@324: smart.EnableSmart(handle, index); moel@324: moel@324: this.index = index; moel@324: this.count = 0; moel@324: moel@324: this.smartAttributes = new List(smartAttributes); moel@324: moel@324: CreateSensors(); moel@324: } moel@324: moel@324: public static AbstractHarddrive CreateInstance(ISmart smart, moel@324: int driveIndex, ISettings settings) moel@324: { moel@324: IntPtr deviceHandle = smart.OpenDrive(driveIndex); moel@324: moel@324: if (deviceHandle == smart.InvalidHandle) moel@324: return null; moel@324: moel@325: string name; moel@325: string firmwareRevision; moel@325: bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, moel@325: driveIndex, out name, out firmwareRevision); moel@324: bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex); moel@324: moel@324: DriveAttributeValue[] values = {}; moel@324: if (smartEnabled) moel@324: values = smart.ReadSmartData(deviceHandle, driveIndex); moel@324: moel@324: smart.CloseHandle(deviceHandle); moel@324: moel@325: if (!nameValid || string.IsNullOrEmpty(name)) moel@324: return null; moel@324: moel@324: foreach (Type type in hddTypes) { moel@324: // get the array of name prefixes for the current type moel@324: NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes( moel@324: typeof(NamePrefixAttribute), true) as NamePrefixAttribute[]; moel@324: moel@324: // get the array of the required SMART attributes for the current type moel@324: RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes( moel@324: typeof(RequireSmartAttribute), true) as RequireSmartAttribute[]; moel@324: moel@324: // check if all required attributes are present moel@324: bool allRequiredAttributesFound = true; moel@324: foreach (var requireAttribute in requiredAttributes) { moel@324: bool adttributeFound = false; moel@324: foreach (DriveAttributeValue value in values) { moel@324: if (value.Identifier == requireAttribute.AttributeId) { moel@324: adttributeFound = true; moel@324: break; moel@324: } moel@324: } moel@324: if (!adttributeFound) { moel@324: allRequiredAttributesFound = false; moel@324: break; moel@324: } moel@324: } moel@324: moel@324: // if an attribute is missing, then try the next type moel@324: if (!allRequiredAttributesFound) moel@324: continue; moel@324: moel@324: // check if there is a matching name prefix for this type moel@324: foreach (NamePrefixAttribute prefix in namePrefixes) { moel@324: if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) moel@325: return Activator.CreateInstance(type, smart, name, firmwareRevision, moel@325: driveIndex, settings) as AbstractHarddrive; moel@324: } moel@324: } moel@324: moel@324: // no matching type has been found moel@324: return null; moel@324: } moel@324: moel@324: private void CreateSensors() { moel@324: sensors = new Dictionary(); moel@324: moel@324: IList> sensorTypeAndChannels = moel@324: new List>(); moel@324: moel@324: DriveAttributeValue[] values = smart.ReadSmartData(handle, index); moel@324: moel@324: foreach (SmartAttribute attribute in smartAttributes) { moel@324: if (!attribute.SensorType.HasValue) moel@324: continue; moel@324: moel@324: bool found = false; moel@324: foreach (DriveAttributeValue value in values) { moel@324: if (value.Identifier == attribute.Identifier) { moel@324: found = true; moel@324: break; moel@324: } moel@324: } moel@324: if (!found) moel@324: continue; moel@324: moel@324: Pair pair = new Pair( moel@324: attribute.SensorType.Value, attribute.SensorChannel); moel@324: moel@324: if (!sensorTypeAndChannels.Contains(pair)) { moel@324: Sensor sensor = new Sensor(attribute.Name, moel@324: attribute.SensorChannel, attribute.SensorType.Value, this, moel@324: settings); moel@324: moel@324: sensors.Add(attribute, sensor); moel@324: sensorTypeAndChannels.Add(pair); moel@324: } moel@324: } moel@324: } moel@324: moel@324: public override HardwareType HardwareType { moel@324: get { return HardwareType.HDD; } moel@324: } moel@324: moel@324: public override ISensor[] Sensors { moel@324: get { moel@324: Sensor[] array = new Sensor[sensors.Count]; moel@324: sensors.Values.CopyTo(array, 0); moel@324: return array; moel@324: } moel@324: } moel@324: moel@324: public override void Update() { moel@324: if (count == 0) { moel@324: DriveAttributeValue[] values = smart.ReadSmartData(handle, index); moel@324: moel@324: foreach (KeyValuePair keyValuePair in sensors) { moel@324: SmartAttribute attribute = keyValuePair.Key; moel@324: foreach (DriveAttributeValue value in values) { moel@324: if (value.Identifier == attribute.Identifier) { moel@324: Sensor sensor = keyValuePair.Value; moel@324: sensor.Value = attribute.ConvertValue(value); moel@324: } moel@324: } moel@324: } moel@324: } moel@324: moel@324: count++; moel@324: count %= UPDATE_DIVIDER; moel@324: } moel@324: moel@324: public override string GetReport() { moel@324: StringBuilder r = new StringBuilder(); moel@324: DriveAttributeValue[] values = smart.ReadSmartData(handle, index); moel@324: DriveThresholdValue[] thresholds = moel@324: smart.ReadSmartThresholds(handle, index); moel@324: moel@324: if (values.Length > 0) { moel@324: r.AppendLine(this.GetType().Name); moel@324: r.AppendLine(); moel@324: r.AppendLine("Drive name: " + name); moel@325: r.AppendLine("Firmware version: " + firmwareRevision); moel@324: r.AppendLine(); moel@324: r.AppendFormat(CultureInfo.InvariantCulture, moel@324: " {0}{1}{2}{3}{4}{5}{6}{7}", moel@324: ("ID").PadRight(3), moel@328: ("Description").PadRight(35), moel@324: ("Raw Value").PadRight(13), moel@324: ("Worst").PadRight(6), moel@324: ("Value").PadRight(6), moel@324: ("Thres").PadRight(6), moel@324: ("Physical").PadRight(8), moel@324: Environment.NewLine); moel@324: moel@324: foreach (DriveAttributeValue value in values) { moel@324: if (value.Identifier == 0x00) moel@324: break; moel@324: moel@324: byte? threshold = null; moel@324: foreach (DriveThresholdValue t in thresholds) { moel@324: if (t.Identifier == value.Identifier) { moel@324: threshold = t.Threshold; moel@324: } moel@324: } moel@324: moel@324: string description = "Unknown"; moel@324: float? physical = null; moel@324: foreach (SmartAttribute a in smartAttributes) { moel@324: if (a.Identifier == value.Identifier) { moel@324: description = a.Name; moel@324: if (a.HasRawValueConversion | a.SensorType.HasValue) moel@324: physical = a.ConvertValue(value); moel@324: else moel@324: physical = null; moel@324: } moel@324: } moel@324: moel@324: string raw = BitConverter.ToString(value.RawValue); moel@324: r.AppendFormat(CultureInfo.InvariantCulture, moel@324: " {0}{1}{2}{3}{4}{5}{6}{7}", moel@324: value.Identifier.ToString("X2").PadRight(3), moel@328: description.PadRight(35), moel@324: raw.Replace("-", "").PadRight(13), moel@324: value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6), moel@324: value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6), moel@324: (threshold.HasValue ? threshold.Value.ToString( moel@324: CultureInfo.InvariantCulture) : "-").PadRight(6), moel@324: (physical.HasValue ? physical.Value.ToString( moel@324: CultureInfo.InvariantCulture) : "-").PadRight(8), moel@324: Environment.NewLine); moel@324: } moel@324: r.AppendLine(); moel@324: } moel@324: moel@324: return r.ToString(); moel@324: } moel@324: moel@324: protected static float RawToInt(byte[] raw, byte value) { moel@324: return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]; moel@324: } moel@324: moel@324: public override void Close() { moel@324: smart.CloseHandle(handle); moel@324: base.Close(); moel@324: } moel@324: moel@324: public override void Traverse(IVisitor visitor) { moel@324: foreach (ISensor sensor in Sensors) moel@324: sensor.Accept(visitor); moel@324: } moel@324: } moel@324: }