Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 340 600962f8a298
child 358 7962499f9cd6
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	Copyright (C) 2010 Paul Werelds
     9   Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
    10 	
    11 */
    12 
    13 using System;
    14 using System.Collections.Generic;
    15 using System.Globalization;
    16 using System.Text;
    17 using OpenHardwareMonitor.Collections;
    18 
    19 namespace OpenHardwareMonitor.Hardware.HDD {
    20   internal abstract class AbstractHarddrive : Hardware {
    21 
    22     private const int UPDATE_DIVIDER = 30; // update only every 30s
    23 
    24     // array of all harddrive types, matching type is searched in this order
    25     private static Type[] hddTypes = {       
    26       typeof(SSDPlextor),
    27       typeof(SSDIntel),
    28       typeof(SSDSandforce),
    29       typeof(SSDIndilinx),
    30       typeof(SSDSamsung),
    31       typeof(GenericHarddisk)
    32     };
    33 
    34     private string firmwareRevision;
    35     private readonly ISmart smart;
    36 
    37     private readonly IntPtr handle;
    38     private readonly int index;
    39     private int count;
    40 
    41     private IList<SmartAttribute> smartAttributes;
    42     private IDictionary<SmartAttribute, Sensor> sensors;
    43 
    44     protected AbstractHarddrive(ISmart smart, string name, 
    45       string firmwareRevision, int index, 
    46       IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
    47       : base(name, new Identifier("hdd",
    48         index.ToString(CultureInfo.InvariantCulture)), settings)
    49     {
    50       this.firmwareRevision = firmwareRevision;
    51       this.smart = smart;
    52       handle = smart.OpenDrive(index);
    53 
    54       smart.EnableSmart(handle, index);
    55 
    56       this.index = index;
    57       this.count = 0;
    58 
    59       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    60 
    61       CreateSensors();
    62     }
    63 
    64     public static AbstractHarddrive CreateInstance(ISmart smart, 
    65       int driveIndex, ISettings settings) 
    66     {
    67       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    68 
    69       if (deviceHandle == smart.InvalidHandle) 
    70         return null;
    71 
    72       string name;
    73       string firmwareRevision;
    74       bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
    75         driveIndex, out name, out firmwareRevision);
    76       bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
    77 
    78       DriveAttributeValue[] values = {};
    79       if (smartEnabled)
    80         values = smart.ReadSmartData(deviceHandle, driveIndex);
    81 
    82       smart.CloseHandle(deviceHandle);
    83 
    84       if (!nameValid || string.IsNullOrEmpty(name)) 
    85         return null;
    86 
    87       foreach (Type type in hddTypes) {
    88         // get the array of name prefixes for the current type
    89         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
    90           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
    91 
    92         // get the array of the required SMART attributes for the current type
    93         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
    94           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
    95 
    96         // check if all required attributes are present
    97         bool allRequiredAttributesFound = true;
    98         foreach (var requireAttribute in requiredAttributes) {
    99           bool adttributeFound = false;
   100           foreach (DriveAttributeValue value in values) {
   101             if (value.Identifier == requireAttribute.AttributeId) {
   102               adttributeFound = true;
   103               break;
   104             }
   105           }
   106           if (!adttributeFound) {
   107             allRequiredAttributesFound = false;
   108             break;
   109           }
   110         }
   111 
   112         // if an attribute is missing, then try the next type
   113         if (!allRequiredAttributesFound)
   114           continue;        
   115 
   116         // check if there is a matching name prefix for this type
   117         foreach (NamePrefixAttribute prefix in namePrefixes) {
   118           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   119             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   120               driveIndex, settings) as AbstractHarddrive;
   121         }
   122       }
   123 
   124       // no matching type has been found
   125       return null;
   126     }
   127 
   128     private void CreateSensors() {
   129       sensors = new Dictionary<SmartAttribute, Sensor>();
   130 
   131       IList<Pair<SensorType, int>> sensorTypeAndChannels = 
   132         new List<Pair<SensorType, int>>();
   133 
   134       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   135 
   136       foreach (SmartAttribute attribute in smartAttributes) {
   137         if (!attribute.SensorType.HasValue) 
   138           continue;
   139 
   140         bool found = false;
   141         foreach (DriveAttributeValue value in values) {
   142           if (value.Identifier == attribute.Identifier) {
   143             found = true;
   144             break;
   145           }
   146         }
   147         if (!found)
   148           continue;
   149 
   150         Pair<SensorType, int> pair = new Pair<SensorType, int>(
   151           attribute.SensorType.Value, attribute.SensorChannel);
   152 
   153         if (!sensorTypeAndChannels.Contains(pair)) {
   154           Sensor sensor = new Sensor(attribute.Name, 
   155             attribute.SensorChannel, attribute.DefaultHiddenSensor, 
   156             attribute.SensorType.Value, this, null, settings);
   157 
   158           sensors.Add(attribute, sensor);
   159           ActivateSensor(sensor);
   160           sensorTypeAndChannels.Add(pair);
   161         }     
   162       }
   163     }
   164 
   165     public override HardwareType HardwareType {
   166       get { return HardwareType.HDD; }
   167     }
   168 
   169     public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
   170 
   171     public override void Update() {
   172       if (count == 0) {
   173         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   174 
   175         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   176           SmartAttribute attribute = keyValuePair.Key;          
   177           foreach (DriveAttributeValue value in values) {
   178             if (value.Identifier == attribute.Identifier) {
   179               Sensor sensor = keyValuePair.Value;
   180               sensor.Value = attribute.ConvertValue(value);
   181             }
   182           }
   183         }
   184 
   185         UpdateAdditionalSensors(values);
   186       }
   187 
   188       count++; 
   189       count %= UPDATE_DIVIDER; 
   190     }
   191 
   192     public override string GetReport() {
   193       StringBuilder r = new StringBuilder();
   194       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   195       DriveThresholdValue[] thresholds = 
   196         smart.ReadSmartThresholds(handle, index);
   197 
   198       if (values.Length > 0) {
   199         r.AppendLine(this.GetType().Name);
   200         r.AppendLine();
   201         r.AppendLine("Drive name: " + name);
   202         r.AppendLine("Firmware version: " + firmwareRevision);
   203         r.AppendLine();
   204         r.AppendFormat(CultureInfo.InvariantCulture, 
   205           " {0}{1}{2}{3}{4}{5}{6}{7}",
   206           ("ID").PadRight(3),
   207           ("Description").PadRight(35),
   208           ("Raw Value").PadRight(13),
   209           ("Worst").PadRight(6),
   210           ("Value").PadRight(6),
   211           ("Thres").PadRight(6),
   212           ("Physical").PadRight(8),
   213           Environment.NewLine);
   214 
   215         foreach (DriveAttributeValue value in values) {
   216           if (value.Identifier == 0x00) 
   217             break;
   218 
   219           byte? threshold = null;
   220           foreach (DriveThresholdValue t in thresholds) {
   221             if (t.Identifier == value.Identifier) {
   222               threshold = t.Threshold;
   223             }
   224           }
   225 
   226           string description = "Unknown";
   227           float? physical = null;
   228           foreach (SmartAttribute a in smartAttributes) {
   229             if (a.Identifier == value.Identifier) {
   230               description = a.Name;
   231               if (a.HasRawValueConversion | a.SensorType.HasValue)
   232                 physical = a.ConvertValue(value);
   233               else
   234                 physical = null;
   235             }
   236           }
   237 
   238           string raw = BitConverter.ToString(value.RawValue);
   239           r.AppendFormat(CultureInfo.InvariantCulture, 
   240             " {0}{1}{2}{3}{4}{5}{6}{7}",
   241             value.Identifier.ToString("X2").PadRight(3),
   242             description.PadRight(35),
   243             raw.Replace("-", "").PadRight(13),
   244             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   245             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   246             (threshold.HasValue ? threshold.Value.ToString(
   247               CultureInfo.InvariantCulture) : "-").PadRight(6),
   248             (physical.HasValue ? physical.Value.ToString(
   249               CultureInfo.InvariantCulture) : "-").PadRight(8),
   250             Environment.NewLine);
   251         }
   252         r.AppendLine();
   253       }
   254 
   255       return r.ToString();
   256     }
   257 
   258     protected static float RawToInt(byte[] raw, byte value) {
   259       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   260     }
   261 
   262     public override void Close() {
   263       smart.CloseHandle(handle);
   264       base.Close();
   265     }
   266 
   267     public override void Traverse(IVisitor visitor) {
   268       foreach (ISensor sensor in Sensors)
   269         sensor.Accept(visitor);
   270     }
   271   }
   272 }