Hardware/HDD/AbstractHarddrive.cs
author StephaneLenclud
Sun, 03 Feb 2013 18:01:50 +0100
branchMiniDisplay
changeset 433 090259cfd699
parent 404 1201889d413a
permissions -rw-r--r--
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
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@409
    72
          if (di.TotalSize > 0)
moel@369
    73
            driveInfoList.Add(new DriveInfo(logicalDrive));
moel@409
    74
        } catch (ArgumentException) {
moel@409
    75
        } catch (IOException) {
moel@409
    76
        } catch (UnauthorizedAccessException) {
moel@409
    77
        }
moel@369
    78
      }
moel@369
    79
      driveInfos = driveInfoList.ToArray();
moel@369
    80
moel@324
    81
      CreateSensors();
moel@324
    82
    }
moel@324
    83
moel@324
    84
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    85
      int driveIndex, ISettings settings) 
moel@324
    86
    {
moel@324
    87
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    88
moel@403
    89
      string name = null;
moel@403
    90
      string firmwareRevision = null;
moel@403
    91
      DriveAttributeValue[] values = { };
moel@324
    92
moel@403
    93
      if (deviceHandle != smart.InvalidHandle) {
moel@403
    94
        bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
moel@325
    95
        driveIndex, out name, out firmwareRevision);
moel@403
    96
        bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
    97
moel@403
    98
        if (smartEnabled)
moel@403
    99
          values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
   100
moel@403
   101
        smart.CloseHandle(deviceHandle);
moel@324
   102
moel@403
   103
        if (!nameValid) {
moel@403
   104
          name = null;
moel@403
   105
          firmwareRevision = null;
moel@403
   106
        }
moel@403
   107
      } else {
moel@403
   108
        string[] logicalDrives = smart.GetLogicalDrives(driveIndex);
moel@403
   109
        if (logicalDrives == null || logicalDrives.Length == 0)
moel@403
   110
          return null;
moel@409
   111
moel@409
   112
        bool hasNonZeroSizeDrive = false;
moel@409
   113
        foreach (string logicalDrive in logicalDrives) {
moel@409
   114
          try {
moel@409
   115
            DriveInfo di = new DriveInfo(logicalDrive);
moel@409
   116
            if (di.TotalSize > 0) {
moel@409
   117
              hasNonZeroSizeDrive = true;
moel@409
   118
              break;
moel@409
   119
            }
moel@409
   120
          } catch (ArgumentException) { 
moel@409
   121
          } catch (IOException) { 
moel@409
   122
          } catch (UnauthorizedAccessException) {
moel@409
   123
          }
moel@409
   124
        }
moel@409
   125
moel@409
   126
        if (!hasNonZeroSizeDrive)
moel@409
   127
          return null;
moel@403
   128
      }
moel@403
   129
moel@403
   130
      if (string.IsNullOrEmpty(name))
moel@403
   131
        name = "Generic Hard Disk";
moel@403
   132
moel@403
   133
      if (string.IsNullOrEmpty(firmwareRevision))
moel@403
   134
        firmwareRevision = "Unknown";
moel@324
   135
moel@324
   136
      foreach (Type type in hddTypes) {
moel@324
   137
        // get the array of name prefixes for the current type
moel@324
   138
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
   139
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
   140
moel@324
   141
        // get the array of the required SMART attributes for the current type
moel@324
   142
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
   143
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
   144
moel@324
   145
        // check if all required attributes are present
moel@324
   146
        bool allRequiredAttributesFound = true;
moel@324
   147
        foreach (var requireAttribute in requiredAttributes) {
moel@324
   148
          bool adttributeFound = false;
moel@324
   149
          foreach (DriveAttributeValue value in values) {
moel@324
   150
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   151
              adttributeFound = true;
moel@324
   152
              break;
moel@324
   153
            }
moel@324
   154
          }
moel@324
   155
          if (!adttributeFound) {
moel@324
   156
            allRequiredAttributesFound = false;
moel@324
   157
            break;
moel@324
   158
          }
moel@324
   159
        }
moel@324
   160
moel@324
   161
        // if an attribute is missing, then try the next type
moel@324
   162
        if (!allRequiredAttributesFound)
moel@324
   163
          continue;        
moel@324
   164
moel@324
   165
        // check if there is a matching name prefix for this type
moel@324
   166
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   167
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   168
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   169
              driveIndex, settings) as AbstractHarddrive;
moel@324
   170
        }
moel@324
   171
      }
moel@324
   172
moel@324
   173
      // no matching type has been found
moel@324
   174
      return null;
moel@324
   175
    }
moel@324
   176
moel@324
   177
    private void CreateSensors() {
moel@324
   178
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   179
moel@403
   180
      if (handle != smart.InvalidHandle) {
moel@403
   181
        IList<Pair<SensorType, int>> sensorTypeAndChannels =
moel@403
   182
          new List<Pair<SensorType, int>>();
moel@324
   183
moel@403
   184
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   185
moel@403
   186
        foreach (SmartAttribute attribute in smartAttributes) {
moel@403
   187
          if (!attribute.SensorType.HasValue)
moel@403
   188
            continue;
moel@324
   189
moel@403
   190
          bool found = false;
moel@403
   191
          foreach (DriveAttributeValue value in values) {
moel@403
   192
            if (value.Identifier == attribute.Identifier) {
moel@403
   193
              found = true;
moel@403
   194
              break;
moel@403
   195
            }
moel@403
   196
          }
moel@403
   197
          if (!found)
moel@403
   198
            continue;
moel@403
   199
moel@403
   200
          Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@403
   201
            attribute.SensorType.Value, attribute.SensorChannel);
moel@403
   202
moel@403
   203
          if (!sensorTypeAndChannels.Contains(pair)) {
moel@403
   204
            Sensor sensor = new Sensor(attribute.Name,
moel@403
   205
              attribute.SensorChannel, attribute.DefaultHiddenSensor,
moel@403
   206
              attribute.SensorType.Value, this, attribute.ParameterDescriptions,
moel@403
   207
              settings);
moel@403
   208
moel@403
   209
            sensors.Add(attribute, sensor);
moel@403
   210
            ActivateSensor(sensor);
moel@403
   211
            sensorTypeAndChannels.Add(pair);
moel@324
   212
          }
moel@324
   213
        }
moel@324
   214
      }
moel@369
   215
moel@369
   216
      if (driveInfos.Length > 0) {
moel@369
   217
        usageSensor = 
moel@369
   218
          new Sensor("Used Space", 0, SensorType.Load, this, settings);
moel@369
   219
        ActivateSensor(usageSensor);
moel@369
   220
      }
moel@324
   221
    }
moel@324
   222
moel@324
   223
    public override HardwareType HardwareType {
moel@324
   224
      get { return HardwareType.HDD; }
moel@324
   225
    }
moel@324
   226
moel@339
   227
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   228
moel@324
   229
    public override void Update() {
moel@324
   230
      if (count == 0) {
moel@403
   231
        if (handle != smart.InvalidHandle) {
moel@403
   232
          DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   233
moel@403
   234
          foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) 
moel@403
   235
          {
moel@403
   236
            SmartAttribute attribute = keyValuePair.Key;
moel@403
   237
            foreach (DriveAttributeValue value in values) {
moel@403
   238
              if (value.Identifier == attribute.Identifier) {
moel@403
   239
                Sensor sensor = keyValuePair.Value;
moel@403
   240
                sensor.Value = attribute.ConvertValue(value, sensor.Parameters);
moel@403
   241
              }
moel@324
   242
            }
moel@324
   243
          }
moel@403
   244
moel@403
   245
          UpdateAdditionalSensors(values);
moel@339
   246
        }
moel@339
   247
moel@369
   248
        if (usageSensor != null) {
moel@369
   249
          long totalSize = 0;
moel@369
   250
          long totalFreeSpace = 0;
moel@385
   251
moel@369
   252
          for (int i = 0; i < driveInfos.Length; i++) {
moel@385
   253
            if (!driveInfos[i].IsReady)
moel@385
   254
              continue;
moel@385
   255
            try {
moel@385
   256
              totalSize += driveInfos[i].TotalSize;
moel@385
   257
              totalFreeSpace += driveInfos[i].TotalFreeSpace;
moel@385
   258
            } catch (IOException) { } catch (UnauthorizedAccessException) { }
moel@369
   259
          }
moel@385
   260
          if (totalSize > 0) {
moel@385
   261
            usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
moel@385
   262
          } else {
moel@385
   263
            usageSensor.Value = null;
moel@385
   264
          }
moel@369
   265
        }
moel@324
   266
      }
moel@324
   267
moel@324
   268
      count++; 
moel@324
   269
      count %= UPDATE_DIVIDER; 
moel@324
   270
    }
moel@324
   271
moel@324
   272
    public override string GetReport() {
moel@324
   273
      StringBuilder r = new StringBuilder();
moel@324
   274
moel@403
   275
      r.AppendLine(this.GetType().Name);
moel@403
   276
      r.AppendLine();
moel@403
   277
      r.AppendLine("Drive name: " + name);
moel@403
   278
      r.AppendLine("Firmware version: " + firmwareRevision);
moel@403
   279
      r.AppendLine();
moel@324
   280
moel@403
   281
      if (handle != smart.InvalidHandle) {
moel@403
   282
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@403
   283
        DriveThresholdValue[] thresholds =
moel@403
   284
          smart.ReadSmartThresholds(handle, index);
moel@324
   285
moel@403
   286
        if (values.Length > 0) {
moel@403
   287
          r.AppendFormat(CultureInfo.InvariantCulture,
moel@403
   288
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@403
   289
            ("ID").PadRight(3),
moel@403
   290
            ("Description").PadRight(35),
moel@403
   291
            ("Raw Value").PadRight(13),
moel@403
   292
            ("Worst").PadRight(6),
moel@403
   293
            ("Value").PadRight(6),
moel@403
   294
            ("Thres").PadRight(6),
moel@403
   295
            ("Physical").PadRight(8),
moel@403
   296
            Environment.NewLine);
moel@403
   297
moel@403
   298
          foreach (DriveAttributeValue value in values) {
moel@403
   299
            if (value.Identifier == 0x00)
moel@403
   300
              break;
moel@403
   301
moel@403
   302
            byte? threshold = null;
moel@403
   303
            foreach (DriveThresholdValue t in thresholds) {
moel@403
   304
              if (t.Identifier == value.Identifier) {
moel@403
   305
                threshold = t.Threshold;
moel@403
   306
              }
moel@324
   307
            }
moel@403
   308
moel@403
   309
            string description = "Unknown";
moel@403
   310
            float? physical = null;
moel@403
   311
            foreach (SmartAttribute a in smartAttributes) {
moel@403
   312
              if (a.Identifier == value.Identifier) {
moel@403
   313
                description = a.Name;
moel@403
   314
                if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@403
   315
                  physical = a.ConvertValue(value, null);
moel@403
   316
                else
moel@403
   317
                  physical = null;
moel@403
   318
              }
moel@403
   319
            }
moel@403
   320
moel@403
   321
            string raw = BitConverter.ToString(value.RawValue);
moel@403
   322
            r.AppendFormat(CultureInfo.InvariantCulture,
moel@403
   323
              " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@403
   324
              value.Identifier.ToString("X2").PadRight(3),
moel@403
   325
              description.PadRight(35),
moel@403
   326
              raw.Replace("-", "").PadRight(13),
moel@403
   327
              value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@403
   328
              value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@403
   329
              (threshold.HasValue ? threshold.Value.ToString(
moel@403
   330
                CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@403
   331
              (physical.HasValue ? physical.Value.ToString(
moel@403
   332
                CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@403
   333
              Environment.NewLine);
moel@324
   334
          }
moel@403
   335
          r.AppendLine();
moel@324
   336
        }
moel@324
   337
      }
moel@324
   338
moel@369
   339
      foreach (DriveInfo di in driveInfos) {
moel@404
   340
        if (!di.IsReady)
moel@404
   341
          continue;
moel@404
   342
        try {
moel@404
   343
          r.AppendLine("Logical drive name: " + di.Name);
moel@404
   344
          r.AppendLine("Format: " + di.DriveFormat);
moel@404
   345
          r.AppendLine("Total size: " + di.TotalSize);
moel@404
   346
          r.AppendLine("Total free space: " + di.TotalFreeSpace);
moel@404
   347
          r.AppendLine();
moel@404
   348
        } catch (IOException) { } catch (UnauthorizedAccessException) { }
moel@369
   349
      }
moel@369
   350
moel@324
   351
      return r.ToString();
moel@324
   352
    }
moel@324
   353
moel@374
   354
    protected static float RawToInt(byte[] raw, byte value,
moel@374
   355
      IReadOnlyArray<IParameter> parameters) 
moel@374
   356
    {
moel@324
   357
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   358
    }
moel@324
   359
moel@324
   360
    public override void Close() {
moel@403
   361
      if (handle != smart.InvalidHandle)
moel@403
   362
        smart.CloseHandle(handle);
moel@403
   363
moel@324
   364
      base.Close();
moel@324
   365
    }
moel@324
   366
moel@324
   367
    public override void Traverse(IVisitor visitor) {
moel@324
   368
      foreach (ISensor sensor in Sensors)
moel@324
   369
        sensor.Accept(visitor);
moel@324
   370
    }
moel@324
   371
  }
moel@324
   372
}