Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sat, 29 Jun 2013 16:12:40 +0000
changeset 407 c9dfdbd59bf8
parent 403 c540cf36b7ce
child 409 2ce8da367490
permissions -rw-r--r--
Added experimental support for AMD family 15h model 1Xh and family 16h CPUs.
moel@324
     1
/*
moel@324
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@324
     6
 
moel@403
     7
  Copyright (C) 2009-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	Copyright (C) 2010 Paul Werelds
moel@344
     9
  Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
moel@344
    10
	
moel@324
    11
*/
moel@324
    12
moel@324
    13
using System;
moel@324
    14
using System.Collections.Generic;
moel@324
    15
using System.Globalization;
moel@369
    16
using System.IO;
moel@324
    17
using System.Text;
moel@324
    18
using OpenHardwareMonitor.Collections;
moel@324
    19
moel@324
    20
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    21
  internal abstract class AbstractHarddrive : Hardware {
moel@324
    22
moel@324
    23
    private const int UPDATE_DIVIDER = 30; // update only every 30s
moel@324
    24
moel@324
    25
    // array of all harddrive types, matching type is searched in this order
moel@324
    26
    private static Type[] hddTypes = {       
moel@324
    27
      typeof(SSDPlextor),
moel@324
    28
      typeof(SSDIntel),
moel@324
    29
      typeof(SSDSandforce),
moel@324
    30
      typeof(SSDIndilinx),
moel@328
    31
      typeof(SSDSamsung),
moel@358
    32
      typeof(SSDMicron),
moel@324
    33
      typeof(GenericHarddisk)
moel@324
    34
    };
moel@324
    35
moel@325
    36
    private string firmwareRevision;
moel@324
    37
    private readonly ISmart smart;
moel@324
    38
moel@324
    39
    private readonly IntPtr handle;
moel@324
    40
    private readonly int index;
moel@324
    41
    private int count;
moel@324
    42
moel@324
    43
    private IList<SmartAttribute> smartAttributes;
moel@324
    44
    private IDictionary<SmartAttribute, Sensor> sensors;
moel@324
    45
moel@369
    46
    private DriveInfo[] driveInfos;
moel@369
    47
    private Sensor usageSensor;
moel@369
    48
moel@325
    49
    protected AbstractHarddrive(ISmart smart, string name, 
moel@325
    50
      string firmwareRevision, int index, 
moel@324
    51
      IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
moel@324
    52
      : base(name, new Identifier("hdd",
moel@324
    53
        index.ToString(CultureInfo.InvariantCulture)), settings)
moel@324
    54
    {
moel@325
    55
      this.firmwareRevision = firmwareRevision;
moel@324
    56
      this.smart = smart;
moel@324
    57
      handle = smart.OpenDrive(index);
moel@324
    58
moel@403
    59
      if (handle != smart.InvalidHandle)
moel@403
    60
        smart.EnableSmart(handle, index);
moel@324
    61
moel@324
    62
      this.index = index;
moel@324
    63
      this.count = 0;
moel@324
    64
moel@324
    65
      this.smartAttributes = new List<SmartAttribute>(smartAttributes);
moel@324
    66
moel@369
    67
      string[] logicalDrives = smart.GetLogicalDrives(index);
moel@369
    68
      List<DriveInfo> driveInfoList = new List<DriveInfo>(logicalDrives.Length);
moel@369
    69
      foreach (string logicalDrive in logicalDrives) {
moel@369
    70
        try {
moel@369
    71
          DriveInfo di = new DriveInfo(logicalDrive);
moel@369
    72
          if (di.TotalSize > 0) 
moel@369
    73
            driveInfoList.Add(new DriveInfo(logicalDrive));
moel@369
    74
        } catch (ArgumentException) { } catch (IOException) { }
moel@369
    75
      }
moel@369
    76
      driveInfos = driveInfoList.ToArray();
moel@369
    77
moel@324
    78
      CreateSensors();
moel@324
    79
    }
moel@324
    80
moel@324
    81
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    82
      int driveIndex, ISettings settings) 
moel@324
    83
    {
moel@324
    84
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    85
moel@403
    86
      string name = null;
moel@403
    87
      string firmwareRevision = null;
moel@403
    88
      DriveAttributeValue[] values = { };
moel@324
    89
moel@403
    90
      if (deviceHandle != smart.InvalidHandle) {
moel@403
    91
        bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
moel@325
    92
        driveIndex, out name, out firmwareRevision);
moel@403
    93
        bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
    94
moel@403
    95
        if (smartEnabled)
moel@403
    96
          values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
    97
moel@403
    98
        smart.CloseHandle(deviceHandle);
moel@324
    99
moel@403
   100
        if (!nameValid) {
moel@403
   101
          name = null;
moel@403
   102
          firmwareRevision = null;
moel@403
   103
        }
moel@403
   104
      } else {
moel@403
   105
        string[] logicalDrives = smart.GetLogicalDrives(driveIndex);
moel@403
   106
        if (logicalDrives == null || logicalDrives.Length == 0)
moel@403
   107
          return null;
moel@403
   108
      }
moel@403
   109
moel@403
   110
      if (string.IsNullOrEmpty(name))
moel@403
   111
        name = "Generic Hard Disk";
moel@403
   112
moel@403
   113
      if (string.IsNullOrEmpty(firmwareRevision))
moel@403
   114
        firmwareRevision = "Unknown";
moel@324
   115
moel@324
   116
      foreach (Type type in hddTypes) {
moel@324
   117
        // get the array of name prefixes for the current type
moel@324
   118
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
   119
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
   120
moel@324
   121
        // get the array of the required SMART attributes for the current type
moel@324
   122
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
   123
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
   124
moel@324
   125
        // check if all required attributes are present
moel@324
   126
        bool allRequiredAttributesFound = true;
moel@324
   127
        foreach (var requireAttribute in requiredAttributes) {
moel@324
   128
          bool adttributeFound = false;
moel@324
   129
          foreach (DriveAttributeValue value in values) {
moel@324
   130
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   131
              adttributeFound = true;
moel@324
   132
              break;
moel@324
   133
            }
moel@324
   134
          }
moel@324
   135
          if (!adttributeFound) {
moel@324
   136
            allRequiredAttributesFound = false;
moel@324
   137
            break;
moel@324
   138
          }
moel@324
   139
        }
moel@324
   140
moel@324
   141
        // if an attribute is missing, then try the next type
moel@324
   142
        if (!allRequiredAttributesFound)
moel@324
   143
          continue;        
moel@324
   144
moel@324
   145
        // check if there is a matching name prefix for this type
moel@324
   146
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   147
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   148
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   149
              driveIndex, settings) as AbstractHarddrive;
moel@324
   150
        }
moel@324
   151
      }
moel@324
   152
moel@324
   153
      // no matching type has been found
moel@324
   154
      return null;
moel@324
   155
    }
moel@324
   156
moel@324
   157
    private void CreateSensors() {
moel@324
   158
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   159
moel@403
   160
      if (handle != smart.InvalidHandle) {
moel@403
   161
        IList<Pair<SensorType, int>> sensorTypeAndChannels =
moel@403
   162
          new List<Pair<SensorType, int>>();
moel@324
   163
moel@403
   164
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   165
moel@403
   166
        foreach (SmartAttribute attribute in smartAttributes) {
moel@403
   167
          if (!attribute.SensorType.HasValue)
moel@403
   168
            continue;
moel@324
   169
moel@403
   170
          bool found = false;
moel@403
   171
          foreach (DriveAttributeValue value in values) {
moel@403
   172
            if (value.Identifier == attribute.Identifier) {
moel@403
   173
              found = true;
moel@403
   174
              break;
moel@403
   175
            }
moel@403
   176
          }
moel@403
   177
          if (!found)
moel@403
   178
            continue;
moel@403
   179
moel@403
   180
          Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@403
   181
            attribute.SensorType.Value, attribute.SensorChannel);
moel@403
   182
moel@403
   183
          if (!sensorTypeAndChannels.Contains(pair)) {
moel@403
   184
            Sensor sensor = new Sensor(attribute.Name,
moel@403
   185
              attribute.SensorChannel, attribute.DefaultHiddenSensor,
moel@403
   186
              attribute.SensorType.Value, this, attribute.ParameterDescriptions,
moel@403
   187
              settings);
moel@403
   188
moel@403
   189
            sensors.Add(attribute, sensor);
moel@403
   190
            ActivateSensor(sensor);
moel@403
   191
            sensorTypeAndChannels.Add(pair);
moel@324
   192
          }
moel@324
   193
        }
moel@324
   194
      }
moel@369
   195
moel@369
   196
      if (driveInfos.Length > 0) {
moel@369
   197
        usageSensor = 
moel@369
   198
          new Sensor("Used Space", 0, SensorType.Load, this, settings);
moel@369
   199
        ActivateSensor(usageSensor);
moel@369
   200
      }
moel@324
   201
    }
moel@324
   202
moel@324
   203
    public override HardwareType HardwareType {
moel@324
   204
      get { return HardwareType.HDD; }
moel@324
   205
    }
moel@324
   206
moel@339
   207
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   208
moel@324
   209
    public override void Update() {
moel@324
   210
      if (count == 0) {
moel@403
   211
        if (handle != smart.InvalidHandle) {
moel@403
   212
          DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   213
moel@403
   214
          foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) 
moel@403
   215
          {
moel@403
   216
            SmartAttribute attribute = keyValuePair.Key;
moel@403
   217
            foreach (DriveAttributeValue value in values) {
moel@403
   218
              if (value.Identifier == attribute.Identifier) {
moel@403
   219
                Sensor sensor = keyValuePair.Value;
moel@403
   220
                sensor.Value = attribute.ConvertValue(value, sensor.Parameters);
moel@403
   221
              }
moel@324
   222
            }
moel@324
   223
          }
moel@403
   224
moel@403
   225
          UpdateAdditionalSensors(values);
moel@339
   226
        }
moel@339
   227
moel@369
   228
        if (usageSensor != null) {
moel@369
   229
          long totalSize = 0;
moel@369
   230
          long totalFreeSpace = 0;
moel@385
   231
moel@369
   232
          for (int i = 0; i < driveInfos.Length; i++) {
moel@385
   233
            if (!driveInfos[i].IsReady)
moel@385
   234
              continue;
moel@385
   235
            try {
moel@385
   236
              totalSize += driveInfos[i].TotalSize;
moel@385
   237
              totalFreeSpace += driveInfos[i].TotalFreeSpace;
moel@385
   238
            } catch (IOException) { } catch (UnauthorizedAccessException) { }
moel@369
   239
          }
moel@385
   240
          if (totalSize > 0) {
moel@385
   241
            usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
moel@385
   242
          } else {
moel@385
   243
            usageSensor.Value = null;
moel@385
   244
          }
moel@369
   245
        }
moel@324
   246
      }
moel@324
   247
moel@324
   248
      count++; 
moel@324
   249
      count %= UPDATE_DIVIDER; 
moel@324
   250
    }
moel@324
   251
moel@324
   252
    public override string GetReport() {
moel@324
   253
      StringBuilder r = new StringBuilder();
moel@324
   254
moel@403
   255
      r.AppendLine(this.GetType().Name);
moel@403
   256
      r.AppendLine();
moel@403
   257
      r.AppendLine("Drive name: " + name);
moel@403
   258
      r.AppendLine("Firmware version: " + firmwareRevision);
moel@403
   259
      r.AppendLine();
moel@324
   260
moel@403
   261
      if (handle != smart.InvalidHandle) {
moel@403
   262
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@403
   263
        DriveThresholdValue[] thresholds =
moel@403
   264
          smart.ReadSmartThresholds(handle, index);
moel@324
   265
moel@403
   266
        if (values.Length > 0) {
moel@403
   267
          r.AppendFormat(CultureInfo.InvariantCulture,
moel@403
   268
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@403
   269
            ("ID").PadRight(3),
moel@403
   270
            ("Description").PadRight(35),
moel@403
   271
            ("Raw Value").PadRight(13),
moel@403
   272
            ("Worst").PadRight(6),
moel@403
   273
            ("Value").PadRight(6),
moel@403
   274
            ("Thres").PadRight(6),
moel@403
   275
            ("Physical").PadRight(8),
moel@403
   276
            Environment.NewLine);
moel@403
   277
moel@403
   278
          foreach (DriveAttributeValue value in values) {
moel@403
   279
            if (value.Identifier == 0x00)
moel@403
   280
              break;
moel@403
   281
moel@403
   282
            byte? threshold = null;
moel@403
   283
            foreach (DriveThresholdValue t in thresholds) {
moel@403
   284
              if (t.Identifier == value.Identifier) {
moel@403
   285
                threshold = t.Threshold;
moel@403
   286
              }
moel@324
   287
            }
moel@403
   288
moel@403
   289
            string description = "Unknown";
moel@403
   290
            float? physical = null;
moel@403
   291
            foreach (SmartAttribute a in smartAttributes) {
moel@403
   292
              if (a.Identifier == value.Identifier) {
moel@403
   293
                description = a.Name;
moel@403
   294
                if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@403
   295
                  physical = a.ConvertValue(value, null);
moel@403
   296
                else
moel@403
   297
                  physical = null;
moel@403
   298
              }
moel@403
   299
            }
moel@403
   300
moel@403
   301
            string raw = BitConverter.ToString(value.RawValue);
moel@403
   302
            r.AppendFormat(CultureInfo.InvariantCulture,
moel@403
   303
              " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@403
   304
              value.Identifier.ToString("X2").PadRight(3),
moel@403
   305
              description.PadRight(35),
moel@403
   306
              raw.Replace("-", "").PadRight(13),
moel@403
   307
              value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@403
   308
              value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@403
   309
              (threshold.HasValue ? threshold.Value.ToString(
moel@403
   310
                CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@403
   311
              (physical.HasValue ? physical.Value.ToString(
moel@403
   312
                CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@403
   313
              Environment.NewLine);
moel@324
   314
          }
moel@403
   315
          r.AppendLine();
moel@324
   316
        }
moel@324
   317
      }
moel@324
   318
moel@369
   319
      foreach (DriveInfo di in driveInfos) {
moel@404
   320
        if (!di.IsReady)
moel@404
   321
          continue;
moel@404
   322
        try {
moel@404
   323
          r.AppendLine("Logical drive name: " + di.Name);
moel@404
   324
          r.AppendLine("Format: " + di.DriveFormat);
moel@404
   325
          r.AppendLine("Total size: " + di.TotalSize);
moel@404
   326
          r.AppendLine("Total free space: " + di.TotalFreeSpace);
moel@404
   327
          r.AppendLine();
moel@404
   328
        } catch (IOException) { } catch (UnauthorizedAccessException) { }
moel@369
   329
      }
moel@369
   330
moel@324
   331
      return r.ToString();
moel@324
   332
    }
moel@324
   333
moel@374
   334
    protected static float RawToInt(byte[] raw, byte value,
moel@374
   335
      IReadOnlyArray<IParameter> parameters) 
moel@374
   336
    {
moel@324
   337
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   338
    }
moel@324
   339
moel@324
   340
    public override void Close() {
moel@403
   341
      if (handle != smart.InvalidHandle)
moel@403
   342
        smart.CloseHandle(handle);
moel@403
   343
moel@324
   344
      base.Close();
moel@324
   345
    }
moel@324
   346
moel@324
   347
    public override void Traverse(IVisitor visitor) {
moel@324
   348
      foreach (ISensor sensor in Sensors)
moel@324
   349
        sensor.Accept(visitor);
moel@324
   350
    }
moel@324
   351
  }
moel@324
   352
}