Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 340 600962f8a298
child 358 7962499f9cd6
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
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@324
    16
using System.Text;
moel@324
    17
using OpenHardwareMonitor.Collections;
moel@324
    18
moel@324
    19
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    20
  internal abstract class AbstractHarddrive : Hardware {
moel@324
    21
moel@324
    22
    private const int UPDATE_DIVIDER = 30; // update only every 30s
moel@324
    23
moel@324
    24
    // array of all harddrive types, matching type is searched in this order
moel@324
    25
    private static Type[] hddTypes = {       
moel@324
    26
      typeof(SSDPlextor),
moel@324
    27
      typeof(SSDIntel),
moel@324
    28
      typeof(SSDSandforce),
moel@324
    29
      typeof(SSDIndilinx),
moel@328
    30
      typeof(SSDSamsung),
moel@324
    31
      typeof(GenericHarddisk)
moel@324
    32
    };
moel@324
    33
moel@325
    34
    private string firmwareRevision;
moel@324
    35
    private readonly ISmart smart;
moel@324
    36
moel@324
    37
    private readonly IntPtr handle;
moel@324
    38
    private readonly int index;
moel@324
    39
    private int count;
moel@324
    40
moel@324
    41
    private IList<SmartAttribute> smartAttributes;
moel@324
    42
    private IDictionary<SmartAttribute, Sensor> sensors;
moel@324
    43
moel@325
    44
    protected AbstractHarddrive(ISmart smart, string name, 
moel@325
    45
      string firmwareRevision, int index, 
moel@324
    46
      IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
moel@324
    47
      : base(name, new Identifier("hdd",
moel@324
    48
        index.ToString(CultureInfo.InvariantCulture)), settings)
moel@324
    49
    {
moel@325
    50
      this.firmwareRevision = firmwareRevision;
moel@324
    51
      this.smart = smart;
moel@324
    52
      handle = smart.OpenDrive(index);
moel@324
    53
moel@324
    54
      smart.EnableSmart(handle, index);
moel@324
    55
moel@324
    56
      this.index = index;
moel@324
    57
      this.count = 0;
moel@324
    58
moel@324
    59
      this.smartAttributes = new List<SmartAttribute>(smartAttributes);
moel@324
    60
moel@324
    61
      CreateSensors();
moel@324
    62
    }
moel@324
    63
moel@324
    64
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    65
      int driveIndex, ISettings settings) 
moel@324
    66
    {
moel@324
    67
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    68
moel@324
    69
      if (deviceHandle == smart.InvalidHandle) 
moel@324
    70
        return null;
moel@324
    71
moel@325
    72
      string name;
moel@325
    73
      string firmwareRevision;
moel@325
    74
      bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
moel@325
    75
        driveIndex, out name, out firmwareRevision);
moel@324
    76
      bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
    77
moel@324
    78
      DriveAttributeValue[] values = {};
moel@324
    79
      if (smartEnabled)
moel@324
    80
        values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
    81
moel@324
    82
      smart.CloseHandle(deviceHandle);
moel@324
    83
moel@325
    84
      if (!nameValid || string.IsNullOrEmpty(name)) 
moel@324
    85
        return null;
moel@324
    86
moel@324
    87
      foreach (Type type in hddTypes) {
moel@324
    88
        // get the array of name prefixes for the current type
moel@324
    89
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
    90
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
    91
moel@324
    92
        // get the array of the required SMART attributes for the current type
moel@324
    93
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
    94
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
    95
moel@324
    96
        // check if all required attributes are present
moel@324
    97
        bool allRequiredAttributesFound = true;
moel@324
    98
        foreach (var requireAttribute in requiredAttributes) {
moel@324
    99
          bool adttributeFound = false;
moel@324
   100
          foreach (DriveAttributeValue value in values) {
moel@324
   101
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   102
              adttributeFound = true;
moel@324
   103
              break;
moel@324
   104
            }
moel@324
   105
          }
moel@324
   106
          if (!adttributeFound) {
moel@324
   107
            allRequiredAttributesFound = false;
moel@324
   108
            break;
moel@324
   109
          }
moel@324
   110
        }
moel@324
   111
moel@324
   112
        // if an attribute is missing, then try the next type
moel@324
   113
        if (!allRequiredAttributesFound)
moel@324
   114
          continue;        
moel@324
   115
moel@324
   116
        // check if there is a matching name prefix for this type
moel@324
   117
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   118
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   119
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   120
              driveIndex, settings) as AbstractHarddrive;
moel@324
   121
        }
moel@324
   122
      }
moel@324
   123
moel@324
   124
      // no matching type has been found
moel@324
   125
      return null;
moel@324
   126
    }
moel@324
   127
moel@324
   128
    private void CreateSensors() {
moel@324
   129
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   130
moel@324
   131
      IList<Pair<SensorType, int>> sensorTypeAndChannels = 
moel@324
   132
        new List<Pair<SensorType, int>>();
moel@324
   133
moel@324
   134
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   135
moel@324
   136
      foreach (SmartAttribute attribute in smartAttributes) {
moel@324
   137
        if (!attribute.SensorType.HasValue) 
moel@324
   138
          continue;
moel@324
   139
moel@324
   140
        bool found = false;
moel@324
   141
        foreach (DriveAttributeValue value in values) {
moel@324
   142
          if (value.Identifier == attribute.Identifier) {
moel@324
   143
            found = true;
moel@324
   144
            break;
moel@324
   145
          }
moel@324
   146
        }
moel@324
   147
        if (!found)
moel@324
   148
          continue;
moel@324
   149
moel@324
   150
        Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@324
   151
          attribute.SensorType.Value, attribute.SensorChannel);
moel@324
   152
moel@324
   153
        if (!sensorTypeAndChannels.Contains(pair)) {
moel@324
   154
          Sensor sensor = new Sensor(attribute.Name, 
moel@340
   155
            attribute.SensorChannel, attribute.DefaultHiddenSensor, 
moel@340
   156
            attribute.SensorType.Value, this, null, settings);
moel@324
   157
moel@324
   158
          sensors.Add(attribute, sensor);
moel@339
   159
          ActivateSensor(sensor);
moel@324
   160
          sensorTypeAndChannels.Add(pair);
moel@324
   161
        }     
moel@324
   162
      }
moel@324
   163
    }
moel@324
   164
moel@324
   165
    public override HardwareType HardwareType {
moel@324
   166
      get { return HardwareType.HDD; }
moel@324
   167
    }
moel@324
   168
moel@339
   169
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   170
moel@324
   171
    public override void Update() {
moel@324
   172
      if (count == 0) {
moel@324
   173
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   174
moel@324
   175
        foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
moel@324
   176
          SmartAttribute attribute = keyValuePair.Key;          
moel@324
   177
          foreach (DriveAttributeValue value in values) {
moel@324
   178
            if (value.Identifier == attribute.Identifier) {
moel@324
   179
              Sensor sensor = keyValuePair.Value;
moel@324
   180
              sensor.Value = attribute.ConvertValue(value);
moel@324
   181
            }
moel@324
   182
          }
moel@339
   183
        }
moel@339
   184
moel@339
   185
        UpdateAdditionalSensors(values);
moel@324
   186
      }
moel@324
   187
moel@324
   188
      count++; 
moel@324
   189
      count %= UPDATE_DIVIDER; 
moel@324
   190
    }
moel@324
   191
moel@324
   192
    public override string GetReport() {
moel@324
   193
      StringBuilder r = new StringBuilder();
moel@324
   194
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   195
      DriveThresholdValue[] thresholds = 
moel@324
   196
        smart.ReadSmartThresholds(handle, index);
moel@324
   197
moel@324
   198
      if (values.Length > 0) {
moel@324
   199
        r.AppendLine(this.GetType().Name);
moel@324
   200
        r.AppendLine();
moel@324
   201
        r.AppendLine("Drive name: " + name);
moel@325
   202
        r.AppendLine("Firmware version: " + firmwareRevision);
moel@324
   203
        r.AppendLine();
moel@324
   204
        r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   205
          " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   206
          ("ID").PadRight(3),
moel@328
   207
          ("Description").PadRight(35),
moel@324
   208
          ("Raw Value").PadRight(13),
moel@324
   209
          ("Worst").PadRight(6),
moel@324
   210
          ("Value").PadRight(6),
moel@324
   211
          ("Thres").PadRight(6),
moel@324
   212
          ("Physical").PadRight(8),
moel@324
   213
          Environment.NewLine);
moel@324
   214
moel@324
   215
        foreach (DriveAttributeValue value in values) {
moel@324
   216
          if (value.Identifier == 0x00) 
moel@324
   217
            break;
moel@324
   218
moel@324
   219
          byte? threshold = null;
moel@324
   220
          foreach (DriveThresholdValue t in thresholds) {
moel@324
   221
            if (t.Identifier == value.Identifier) {
moel@324
   222
              threshold = t.Threshold;
moel@324
   223
            }
moel@324
   224
          }
moel@324
   225
moel@324
   226
          string description = "Unknown";
moel@324
   227
          float? physical = null;
moel@324
   228
          foreach (SmartAttribute a in smartAttributes) {
moel@324
   229
            if (a.Identifier == value.Identifier) {
moel@324
   230
              description = a.Name;
moel@324
   231
              if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@324
   232
                physical = a.ConvertValue(value);
moel@324
   233
              else
moel@324
   234
                physical = null;
moel@324
   235
            }
moel@324
   236
          }
moel@324
   237
moel@324
   238
          string raw = BitConverter.ToString(value.RawValue);
moel@324
   239
          r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   240
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   241
            value.Identifier.ToString("X2").PadRight(3),
moel@328
   242
            description.PadRight(35),
moel@324
   243
            raw.Replace("-", "").PadRight(13),
moel@324
   244
            value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   245
            value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   246
            (threshold.HasValue ? threshold.Value.ToString(
moel@324
   247
              CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@324
   248
            (physical.HasValue ? physical.Value.ToString(
moel@324
   249
              CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@324
   250
            Environment.NewLine);
moel@324
   251
        }
moel@324
   252
        r.AppendLine();
moel@324
   253
      }
moel@324
   254
moel@324
   255
      return r.ToString();
moel@324
   256
    }
moel@324
   257
moel@324
   258
    protected static float RawToInt(byte[] raw, byte value) {
moel@324
   259
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   260
    }
moel@324
   261
moel@324
   262
    public override void Close() {
moel@324
   263
      smart.CloseHandle(handle);
moel@324
   264
      base.Close();
moel@324
   265
    }
moel@324
   266
moel@324
   267
    public override void Traverse(IVisitor visitor) {
moel@324
   268
      foreach (ISensor sensor in Sensors)
moel@324
   269
        sensor.Accept(visitor);
moel@324
   270
    }
moel@324
   271
  }
moel@324
   272
}