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