Hardware/HDD/AbstractHarddrive.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
changeset 402 ded1323b61ee
parent 374 ea86cea126bc
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
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
}