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