Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Mon, 23 Jul 2012 21:54:35 +0000
changeset 370 8e4dedc41924
parent 358 7962499f9cd6
child 374 ea86cea126bc
permissions -rw-r--r--
Added a RAM hardware and sensor, fixed Issue 115.
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@340
   172
            attribute.SensorType.Value, this, null, settings);
moel@324
   173
moel@324
   174
          sensors.Add(attribute, sensor);
moel@339
   175
          ActivateSensor(sensor);
moel@324
   176
          sensorTypeAndChannels.Add(pair);
moel@324
   177
        }     
moel@324
   178
      }
moel@369
   179
moel@369
   180
      if (driveInfos.Length > 0) {
moel@369
   181
        usageSensor = 
moel@369
   182
          new Sensor("Used Space", 0, SensorType.Load, this, settings);
moel@369
   183
        ActivateSensor(usageSensor);
moel@369
   184
      }
moel@324
   185
    }
moel@324
   186
moel@324
   187
    public override HardwareType HardwareType {
moel@324
   188
      get { return HardwareType.HDD; }
moel@324
   189
    }
moel@324
   190
moel@339
   191
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   192
moel@324
   193
    public override void Update() {
moel@324
   194
      if (count == 0) {
moel@324
   195
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   196
moel@324
   197
        foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
moel@324
   198
          SmartAttribute attribute = keyValuePair.Key;          
moel@324
   199
          foreach (DriveAttributeValue value in values) {
moel@324
   200
            if (value.Identifier == attribute.Identifier) {
moel@324
   201
              Sensor sensor = keyValuePair.Value;
moel@324
   202
              sensor.Value = attribute.ConvertValue(value);
moel@324
   203
            }
moel@324
   204
          }
moel@339
   205
        }
moel@339
   206
moel@339
   207
        UpdateAdditionalSensors(values);
moel@369
   208
moel@369
   209
        if (usageSensor != null) {
moel@369
   210
          long totalSize = 0;
moel@369
   211
          long totalFreeSpace = 0;
moel@369
   212
          for (int i = 0; i < driveInfos.Length; i++) {
moel@369
   213
            totalSize += driveInfos[i].TotalSize;
moel@369
   214
            totalFreeSpace += driveInfos[i].TotalFreeSpace;
moel@369
   215
          }
moel@369
   216
          usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
moel@369
   217
        }
moel@324
   218
      }
moel@324
   219
moel@324
   220
      count++; 
moel@324
   221
      count %= UPDATE_DIVIDER; 
moel@324
   222
    }
moel@324
   223
moel@324
   224
    public override string GetReport() {
moel@324
   225
      StringBuilder r = new StringBuilder();
moel@324
   226
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   227
      DriveThresholdValue[] thresholds = 
moel@324
   228
        smart.ReadSmartThresholds(handle, index);
moel@324
   229
moel@324
   230
      if (values.Length > 0) {
moel@324
   231
        r.AppendLine(this.GetType().Name);
moel@324
   232
        r.AppendLine();
moel@324
   233
        r.AppendLine("Drive name: " + name);
moel@325
   234
        r.AppendLine("Firmware version: " + firmwareRevision);
moel@369
   235
        r.AppendLine();    
moel@324
   236
        r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   237
          " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   238
          ("ID").PadRight(3),
moel@328
   239
          ("Description").PadRight(35),
moel@324
   240
          ("Raw Value").PadRight(13),
moel@324
   241
          ("Worst").PadRight(6),
moel@324
   242
          ("Value").PadRight(6),
moel@324
   243
          ("Thres").PadRight(6),
moel@324
   244
          ("Physical").PadRight(8),
moel@324
   245
          Environment.NewLine);
moel@324
   246
moel@324
   247
        foreach (DriveAttributeValue value in values) {
moel@324
   248
          if (value.Identifier == 0x00) 
moel@324
   249
            break;
moel@324
   250
moel@324
   251
          byte? threshold = null;
moel@324
   252
          foreach (DriveThresholdValue t in thresholds) {
moel@324
   253
            if (t.Identifier == value.Identifier) {
moel@324
   254
              threshold = t.Threshold;
moel@324
   255
            }
moel@324
   256
          }
moel@324
   257
moel@324
   258
          string description = "Unknown";
moel@324
   259
          float? physical = null;
moel@324
   260
          foreach (SmartAttribute a in smartAttributes) {
moel@324
   261
            if (a.Identifier == value.Identifier) {
moel@324
   262
              description = a.Name;
moel@324
   263
              if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@324
   264
                physical = a.ConvertValue(value);
moel@324
   265
              else
moel@324
   266
                physical = null;
moel@324
   267
            }
moel@324
   268
          }
moel@324
   269
moel@324
   270
          string raw = BitConverter.ToString(value.RawValue);
moel@324
   271
          r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   272
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   273
            value.Identifier.ToString("X2").PadRight(3),
moel@328
   274
            description.PadRight(35),
moel@324
   275
            raw.Replace("-", "").PadRight(13),
moel@324
   276
            value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   277
            value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   278
            (threshold.HasValue ? threshold.Value.ToString(
moel@324
   279
              CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@324
   280
            (physical.HasValue ? physical.Value.ToString(
moel@324
   281
              CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@324
   282
            Environment.NewLine);
moel@324
   283
        }
moel@324
   284
        r.AppendLine();
moel@324
   285
      }
moel@324
   286
moel@369
   287
      foreach (DriveInfo di in driveInfos) {
moel@369
   288
        r.AppendLine("Logical drive name: " + di.Name);
moel@369
   289
        r.AppendLine("Format: " + di.DriveFormat);
moel@369
   290
        r.AppendLine("Total size: " + di.TotalSize);
moel@369
   291
        r.AppendLine("Total free space: " + di.TotalFreeSpace);
moel@369
   292
        r.AppendLine();
moel@369
   293
      }
moel@369
   294
moel@324
   295
      return r.ToString();
moel@324
   296
    }
moel@324
   297
moel@324
   298
    protected static float RawToInt(byte[] raw, byte value) {
moel@324
   299
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   300
    }
moel@324
   301
moel@324
   302
    public override void Close() {
moel@324
   303
      smart.CloseHandle(handle);
moel@324
   304
      base.Close();
moel@324
   305
    }
moel@324
   306
moel@324
   307
    public override void Traverse(IVisitor visitor) {
moel@324
   308
      foreach (ISensor sensor in Sensors)
moel@324
   309
        sensor.Accept(visitor);
moel@324
   310
    }
moel@324
   311
  }
moel@324
   312
}