Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Mon, 02 Jan 2012 18:44:19 +0000
changeset 328 f837f9f0973e
parent 325 4c31341a4800
child 339 07a6126a4796
permissions -rw-r--r--
Added SMART support for Samsung SSDs.
     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(SSDSamsung),
    58       typeof(GenericHarddisk)
    59     };
    60 
    61     private string firmwareRevision;
    62     private readonly ISmart smart;
    63 
    64     private readonly IntPtr handle;
    65     private readonly int index;
    66     private int count;
    67 
    68     private IList<SmartAttribute> smartAttributes;
    69     private IDictionary<SmartAttribute, Sensor> sensors;
    70 
    71     protected AbstractHarddrive(ISmart smart, string name, 
    72       string firmwareRevision, int index, 
    73       IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
    74       : base(name, new Identifier("hdd",
    75         index.ToString(CultureInfo.InvariantCulture)), settings)
    76     {
    77       this.firmwareRevision = firmwareRevision;
    78       this.smart = smart;
    79       handle = smart.OpenDrive(index);
    80 
    81       smart.EnableSmart(handle, index);
    82 
    83       this.index = index;
    84       this.count = 0;
    85 
    86       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    87 
    88       CreateSensors();
    89     }
    90 
    91     public static AbstractHarddrive CreateInstance(ISmart smart, 
    92       int driveIndex, ISettings settings) 
    93     {
    94       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    95 
    96       if (deviceHandle == smart.InvalidHandle) 
    97         return null;
    98 
    99       string name;
   100       string firmwareRevision;
   101       bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
   102         driveIndex, out name, out firmwareRevision);
   103       bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
   104 
   105       DriveAttributeValue[] values = {};
   106       if (smartEnabled)
   107         values = smart.ReadSmartData(deviceHandle, driveIndex);
   108 
   109       smart.CloseHandle(deviceHandle);
   110 
   111       if (!nameValid || string.IsNullOrEmpty(name)) 
   112         return null;
   113 
   114       foreach (Type type in hddTypes) {
   115         // get the array of name prefixes for the current type
   116         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
   117           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
   118 
   119         // get the array of the required SMART attributes for the current type
   120         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
   121           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
   122 
   123         // check if all required attributes are present
   124         bool allRequiredAttributesFound = true;
   125         foreach (var requireAttribute in requiredAttributes) {
   126           bool adttributeFound = false;
   127           foreach (DriveAttributeValue value in values) {
   128             if (value.Identifier == requireAttribute.AttributeId) {
   129               adttributeFound = true;
   130               break;
   131             }
   132           }
   133           if (!adttributeFound) {
   134             allRequiredAttributesFound = false;
   135             break;
   136           }
   137         }
   138 
   139         // if an attribute is missing, then try the next type
   140         if (!allRequiredAttributesFound)
   141           continue;        
   142 
   143         // check if there is a matching name prefix for this type
   144         foreach (NamePrefixAttribute prefix in namePrefixes) {
   145           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   146             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   147               driveIndex, settings) as AbstractHarddrive;
   148         }
   149       }
   150 
   151       // no matching type has been found
   152       return null;
   153     }
   154 
   155     private void CreateSensors() {
   156       sensors = new Dictionary<SmartAttribute, Sensor>();
   157 
   158       IList<Pair<SensorType, int>> sensorTypeAndChannels = 
   159         new List<Pair<SensorType, int>>();
   160 
   161       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   162 
   163       foreach (SmartAttribute attribute in smartAttributes) {
   164         if (!attribute.SensorType.HasValue) 
   165           continue;
   166 
   167         bool found = false;
   168         foreach (DriveAttributeValue value in values) {
   169           if (value.Identifier == attribute.Identifier) {
   170             found = true;
   171             break;
   172           }
   173         }
   174         if (!found)
   175           continue;
   176 
   177         Pair<SensorType, int> pair = new Pair<SensorType, int>(
   178           attribute.SensorType.Value, attribute.SensorChannel);
   179 
   180         if (!sensorTypeAndChannels.Contains(pair)) {
   181           Sensor sensor = new Sensor(attribute.Name, 
   182             attribute.SensorChannel, attribute.SensorType.Value, this, 
   183             settings);
   184 
   185           sensors.Add(attribute, sensor);
   186           sensorTypeAndChannels.Add(pair);
   187         }     
   188       }
   189     }
   190 
   191     public override HardwareType HardwareType {
   192       get { return HardwareType.HDD; }
   193     }
   194 
   195     public override ISensor[] Sensors {
   196       get {
   197         Sensor[] array = new Sensor[sensors.Count];
   198         sensors.Values.CopyTo(array, 0);
   199         return array;
   200       }
   201     }
   202 
   203     public override void Update() {
   204       if (count == 0) {
   205         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   206 
   207         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   208           SmartAttribute attribute = keyValuePair.Key;          
   209           foreach (DriveAttributeValue value in values) {
   210             if (value.Identifier == attribute.Identifier) {
   211               Sensor sensor = keyValuePair.Value;
   212               sensor.Value = attribute.ConvertValue(value);
   213             }
   214           }
   215         }        
   216       }
   217 
   218       count++; 
   219       count %= UPDATE_DIVIDER; 
   220     }
   221 
   222     public override string GetReport() {
   223       StringBuilder r = new StringBuilder();
   224       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   225       DriveThresholdValue[] thresholds = 
   226         smart.ReadSmartThresholds(handle, index);
   227 
   228       if (values.Length > 0) {
   229         r.AppendLine(this.GetType().Name);
   230         r.AppendLine();
   231         r.AppendLine("Drive name: " + name);
   232         r.AppendLine("Firmware version: " + firmwareRevision);
   233         r.AppendLine();
   234         r.AppendFormat(CultureInfo.InvariantCulture, 
   235           " {0}{1}{2}{3}{4}{5}{6}{7}",
   236           ("ID").PadRight(3),
   237           ("Description").PadRight(35),
   238           ("Raw Value").PadRight(13),
   239           ("Worst").PadRight(6),
   240           ("Value").PadRight(6),
   241           ("Thres").PadRight(6),
   242           ("Physical").PadRight(8),
   243           Environment.NewLine);
   244 
   245         foreach (DriveAttributeValue value in values) {
   246           if (value.Identifier == 0x00) 
   247             break;
   248 
   249           byte? threshold = null;
   250           foreach (DriveThresholdValue t in thresholds) {
   251             if (t.Identifier == value.Identifier) {
   252               threshold = t.Threshold;
   253             }
   254           }
   255 
   256           string description = "Unknown";
   257           float? physical = null;
   258           foreach (SmartAttribute a in smartAttributes) {
   259             if (a.Identifier == value.Identifier) {
   260               description = a.Name;
   261               if (a.HasRawValueConversion | a.SensorType.HasValue)
   262                 physical = a.ConvertValue(value);
   263               else
   264                 physical = null;
   265             }
   266           }
   267 
   268           string raw = BitConverter.ToString(value.RawValue);
   269           r.AppendFormat(CultureInfo.InvariantCulture, 
   270             " {0}{1}{2}{3}{4}{5}{6}{7}",
   271             value.Identifier.ToString("X2").PadRight(3),
   272             description.PadRight(35),
   273             raw.Replace("-", "").PadRight(13),
   274             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   275             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   276             (threshold.HasValue ? threshold.Value.ToString(
   277               CultureInfo.InvariantCulture) : "-").PadRight(6),
   278             (physical.HasValue ? physical.Value.ToString(
   279               CultureInfo.InvariantCulture) : "-").PadRight(8),
   280             Environment.NewLine);
   281         }
   282         r.AppendLine();
   283       }
   284 
   285       return r.ToString();
   286     }
   287 
   288     protected static float RawToInt(byte[] raw, byte value) {
   289       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   290     }
   291 
   292     public override void Close() {
   293       smart.CloseHandle(handle);
   294       base.Close();
   295     }
   296 
   297     public override void Traverse(IVisitor visitor) {
   298       foreach (ISensor sensor in Sensors)
   299         sensor.Accept(visitor);
   300     }
   301   }
   302 }