Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 01 Jan 2012 10:14:42 +0000
changeset 325 4c31341a4800
parent 324 c6ee430d6995
child 328 f837f9f0973e
permissions -rw-r--r--
Added the hard drive firmware version to the report. This could be important if the SMART attribute layout changes with firmware versions on some drives.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2012
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s): 
    23     Paul Werelds
    24     Roland Reinl <roland-reinl@gmx.de>
    25 
    26   Alternatively, the contents of this file may be used under the terms of
    27   either the GNU General Public License Version 2 or later (the "GPL"), or
    28   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    29   in which case the provisions of the GPL or the LGPL are applicable instead
    30   of those above. If you wish to allow use of your version of this file only
    31   under the terms of either the GPL or the LGPL, and not to allow others to
    32   use your version of this file under the terms of the MPL, indicate your
    33   decision by deleting the provisions above and replace them with the notice
    34   and other provisions required by the GPL or the LGPL. If you do not delete
    35   the provisions above, a recipient may use your version of this file under
    36   the terms of any one of the MPL, the GPL or the LGPL.
    37  
    38 */
    39 
    40 using System;
    41 using System.Collections.Generic;
    42 using System.Globalization;
    43 using System.Text;
    44 using OpenHardwareMonitor.Collections;
    45 
    46 namespace OpenHardwareMonitor.Hardware.HDD {
    47   internal abstract class AbstractHarddrive : Hardware {
    48 
    49     private const int UPDATE_DIVIDER = 30; // update only every 30s
    50 
    51     // array of all harddrive types, matching type is searched in this order
    52     private static Type[] hddTypes = {       
    53       typeof(SSDPlextor),
    54       typeof(SSDIntel),
    55       typeof(SSDSandforce),
    56       typeof(SSDIndilinx),
    57       typeof(GenericHarddisk)
    58     };
    59 
    60     private string firmwareRevision;
    61     private readonly ISmart smart;
    62 
    63     private readonly IntPtr handle;
    64     private readonly int index;
    65     private int count;
    66 
    67     private IList<SmartAttribute> smartAttributes;
    68     private IDictionary<SmartAttribute, Sensor> sensors;
    69 
    70     protected AbstractHarddrive(ISmart smart, string name, 
    71       string firmwareRevision, int index, 
    72       IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
    73       : base(name, new Identifier("hdd",
    74         index.ToString(CultureInfo.InvariantCulture)), settings)
    75     {
    76       this.firmwareRevision = firmwareRevision;
    77       this.smart = smart;
    78       handle = smart.OpenDrive(index);
    79 
    80       smart.EnableSmart(handle, index);
    81 
    82       this.index = index;
    83       this.count = 0;
    84 
    85       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    86 
    87       CreateSensors();
    88     }
    89 
    90     public static AbstractHarddrive CreateInstance(ISmart smart, 
    91       int driveIndex, ISettings settings) 
    92     {
    93       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    94 
    95       if (deviceHandle == smart.InvalidHandle) 
    96         return null;
    97 
    98       string name;
    99       string firmwareRevision;
   100       bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
   101         driveIndex, out name, out firmwareRevision);
   102       bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
   103 
   104       DriveAttributeValue[] values = {};
   105       if (smartEnabled)
   106         values = smart.ReadSmartData(deviceHandle, driveIndex);
   107 
   108       smart.CloseHandle(deviceHandle);
   109 
   110       if (!nameValid || string.IsNullOrEmpty(name)) 
   111         return null;
   112 
   113       foreach (Type type in hddTypes) {
   114         // get the array of name prefixes for the current type
   115         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
   116           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
   117 
   118         // get the array of the required SMART attributes for the current type
   119         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
   120           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
   121 
   122         // check if all required attributes are present
   123         bool allRequiredAttributesFound = true;
   124         foreach (var requireAttribute in requiredAttributes) {
   125           bool adttributeFound = false;
   126           foreach (DriveAttributeValue value in values) {
   127             if (value.Identifier == requireAttribute.AttributeId) {
   128               adttributeFound = true;
   129               break;
   130             }
   131           }
   132           if (!adttributeFound) {
   133             allRequiredAttributesFound = false;
   134             break;
   135           }
   136         }
   137 
   138         // if an attribute is missing, then try the next type
   139         if (!allRequiredAttributesFound)
   140           continue;        
   141 
   142         // check if there is a matching name prefix for this type
   143         foreach (NamePrefixAttribute prefix in namePrefixes) {
   144           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   145             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   146               driveIndex, settings) as AbstractHarddrive;
   147         }
   148       }
   149 
   150       // no matching type has been found
   151       return null;
   152     }
   153 
   154     private void CreateSensors() {
   155       sensors = new Dictionary<SmartAttribute, Sensor>();
   156 
   157       IList<Pair<SensorType, int>> sensorTypeAndChannels = 
   158         new List<Pair<SensorType, int>>();
   159 
   160       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   161 
   162       foreach (SmartAttribute attribute in smartAttributes) {
   163         if (!attribute.SensorType.HasValue) 
   164           continue;
   165 
   166         bool found = false;
   167         foreach (DriveAttributeValue value in values) {
   168           if (value.Identifier == attribute.Identifier) {
   169             found = true;
   170             break;
   171           }
   172         }
   173         if (!found)
   174           continue;
   175 
   176         Pair<SensorType, int> pair = new Pair<SensorType, int>(
   177           attribute.SensorType.Value, attribute.SensorChannel);
   178 
   179         if (!sensorTypeAndChannels.Contains(pair)) {
   180           Sensor sensor = new Sensor(attribute.Name, 
   181             attribute.SensorChannel, attribute.SensorType.Value, this, 
   182             settings);
   183 
   184           sensors.Add(attribute, sensor);
   185           sensorTypeAndChannels.Add(pair);
   186         }     
   187       }
   188     }
   189 
   190     public override HardwareType HardwareType {
   191       get { return HardwareType.HDD; }
   192     }
   193 
   194     public override ISensor[] Sensors {
   195       get {
   196         Sensor[] array = new Sensor[sensors.Count];
   197         sensors.Values.CopyTo(array, 0);
   198         return array;
   199       }
   200     }
   201 
   202     public override void Update() {
   203       if (count == 0) {
   204         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   205 
   206         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   207           SmartAttribute attribute = keyValuePair.Key;          
   208           foreach (DriveAttributeValue value in values) {
   209             if (value.Identifier == attribute.Identifier) {
   210               Sensor sensor = keyValuePair.Value;
   211               sensor.Value = attribute.ConvertValue(value);
   212             }
   213           }
   214         }        
   215       }
   216 
   217       count++; 
   218       count %= UPDATE_DIVIDER; 
   219     }
   220 
   221     public override string GetReport() {
   222       StringBuilder r = new StringBuilder();
   223       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   224       DriveThresholdValue[] thresholds = 
   225         smart.ReadSmartThresholds(handle, index);
   226 
   227       if (values.Length > 0) {
   228         r.AppendLine(this.GetType().Name);
   229         r.AppendLine();
   230         r.AppendLine("Drive name: " + name);
   231         r.AppendLine("Firmware version: " + firmwareRevision);
   232         r.AppendLine();
   233         r.AppendFormat(CultureInfo.InvariantCulture, 
   234           " {0}{1}{2}{3}{4}{5}{6}{7}",
   235           ("ID").PadRight(3),
   236           ("Description").PadRight(32),
   237           ("Raw Value").PadRight(13),
   238           ("Worst").PadRight(6),
   239           ("Value").PadRight(6),
   240           ("Thres").PadRight(6),
   241           ("Physical").PadRight(8),
   242           Environment.NewLine);
   243 
   244         foreach (DriveAttributeValue value in values) {
   245           if (value.Identifier == 0x00) 
   246             break;
   247 
   248           byte? threshold = null;
   249           foreach (DriveThresholdValue t in thresholds) {
   250             if (t.Identifier == value.Identifier) {
   251               threshold = t.Threshold;
   252             }
   253           }
   254 
   255           string description = "Unknown";
   256           float? physical = null;
   257           foreach (SmartAttribute a in smartAttributes) {
   258             if (a.Identifier == value.Identifier) {
   259               description = a.Name;
   260               if (a.HasRawValueConversion | a.SensorType.HasValue)
   261                 physical = a.ConvertValue(value);
   262               else
   263                 physical = null;
   264             }
   265           }
   266 
   267           string raw = BitConverter.ToString(value.RawValue);
   268           r.AppendFormat(CultureInfo.InvariantCulture, 
   269             " {0}{1}{2}{3}{4}{5}{6}{7}",
   270             value.Identifier.ToString("X2").PadRight(3),
   271             description.PadRight(32),
   272             raw.Replace("-", "").PadRight(13),
   273             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   274             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   275             (threshold.HasValue ? threshold.Value.ToString(
   276               CultureInfo.InvariantCulture) : "-").PadRight(6),
   277             (physical.HasValue ? physical.Value.ToString(
   278               CultureInfo.InvariantCulture) : "-").PadRight(8),
   279             Environment.NewLine);
   280         }
   281         r.AppendLine();
   282       }
   283 
   284       return r.ToString();
   285     }
   286 
   287     protected static float RawToInt(byte[] raw, byte value) {
   288       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   289     }
   290 
   291     public override void Close() {
   292       smart.CloseHandle(handle);
   293       base.Close();
   294     }
   295 
   296     public override void Traverse(IVisitor visitor) {
   297       foreach (ISensor sensor in Sensors)
   298         sensor.Accept(visitor);
   299     }
   300   }
   301 }