Hardware/HDD/HDDGroup.cs
author moel.mich
Mon, 07 Feb 2011 22:06:58 +0000
changeset 253 0044b05a3094
parent 233 c5139c236200
permissions -rw-r--r--
Fixed Issue 162.
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@1
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
paulwerelds@204
    22
  Contributor(s): Paul Werelds
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Collections.Generic;
moel@205
    40
using System.Globalization;
paulwerelds@204
    41
using System.Text;
moel@1
    42
moel@1
    43
namespace OpenHardwareMonitor.Hardware.HDD {
moel@165
    44
  internal class HDDGroup : IGroup {
moel@1
    45
moel@1
    46
    private const int MAX_DRIVES = 32;
moel@1
    47
moel@195
    48
    private readonly List<HDD> hardware = new List<HDD>();
moel@1
    49
moel@165
    50
    public HDDGroup(ISettings settings) {
paulwerelds@204
    51
      int p = (int)Environment.OSVersion.Platform;
paulwerelds@204
    52
      if (p == 4 || p == 128) return;
moel@1
    53
paulwerelds@204
    54
      for (int drive = 0; drive < MAX_DRIVES; drive++) {
paulwerelds@204
    55
        IntPtr handle = SMART.OpenPhysicalDrive(drive);
moel@1
    56
paulwerelds@204
    57
        if (handle == SMART.INVALID_HANDLE_VALUE)
paulwerelds@204
    58
          continue;
paulwerelds@204
    59
paulwerelds@204
    60
        if (!SMART.EnableSmart(handle, drive)) {
paulwerelds@204
    61
          SMART.CloseHandle(handle);
paulwerelds@204
    62
          continue;
paulwerelds@204
    63
        }
paulwerelds@204
    64
paulwerelds@204
    65
        string name = SMART.ReadName(handle, drive);
paulwerelds@204
    66
        if (name == null) {
paulwerelds@204
    67
          SMART.CloseHandle(handle);
paulwerelds@204
    68
          continue;
paulwerelds@204
    69
        }
paulwerelds@204
    70
paulwerelds@233
    71
        SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
paulwerelds@218
    72
        
paulwerelds@233
    73
        if (attributes.Length < 1) {
moel@205
    74
          SMART.CloseHandle(handle);
moel@205
    75
          continue;
moel@205
    76
        }
paulwerelds@204
    77
moel@231
    78
        SMART.AttributeID ssdLifeID = GetSSDLifeID(attributes);
moel@231
    79
        if (ssdLifeID == SMART.AttributeID.None) {
paulwerelds@218
    80
          SMART.AttributeID temperatureID = GetTemperatureIndex(attributes);
paulwerelds@204
    81
moel@231
    82
          if (temperatureID != SMART.AttributeID.None) {
moel@231
    83
            hardware.Add(new HDD(name, handle, drive, temperatureID, 
moel@231
    84
              SMART.AttributeID.None, settings));
paulwerelds@218
    85
            continue;
moel@205
    86
          }
paulwerelds@218
    87
        } else {
moel@231
    88
          hardware.Add(new HDD(name, handle, drive, SMART.AttributeID.None, 
moel@231
    89
            ssdLifeID, settings));
moel@205
    90
          continue;
paulwerelds@204
    91
        }
paulwerelds@218
    92
        
paulwerelds@204
    93
        SMART.CloseHandle(handle);
moel@1
    94
      }
moel@1
    95
    }
moel@1
    96
paulwerelds@233
    97
    private SMART.AttributeID GetSSDLifeID(SMART.DriveAttribute[] attributes) {
paulwerelds@233
    98
      // ID E9 is present on Intel, JM, SF and Samsung (different meanings)
paulwerelds@218
    99
      // ID D2 is present on Indilinx
paulwerelds@218
   100
      // Neither ID has been found on a mechanical hard drive (yet),
paulwerelds@233
   101
      // so this seems like a good way to check if it's an SSD.
moel@231
   102
      bool isKnownSSD = (
paulwerelds@233
   103
        Array.Exists(attributes, attr => attr.ID == new SMART.AttributeID(0xE9)) ||
paulwerelds@233
   104
        Array.Exists(attributes, attr => attr.ID == new SMART.AttributeID(0xD2))
paulwerelds@218
   105
      );
paulwerelds@218
   106
moel@231
   107
      if (!isKnownSSD) return SMART.AttributeID.None;
paulwerelds@218
   108
paulwerelds@218
   109
      // We start with a traditional loop, because there are 4 unique ID's
paulwerelds@218
   110
      // that potentially identify one of the vendors
paulwerelds@233
   111
      for (int i = 0; i < attributes.Length; i++) {
moel@231
   112
        if (attributes[i].ID == SMART.SamsungAttributes.RemainingLife)
moel@231
   113
          return SMART.SamsungAttributes.RemainingLife;
paulwerelds@233
   114
        
paulwerelds@233
   115
        if (attributes[i].ID == SMART.SandForceAttributes.ProgramFailCount)
moel@231
   116
          return  SMART.SandForceAttributes.RemainingLife;
paulwerelds@233
   117
        
paulwerelds@233
   118
        if (attributes[i].ID == SMART.IndilinxAttributes.UnknownUnique)   
paulwerelds@233
   119
          return SMART.IndilinxAttributes.RemainingLife;
paulwerelds@218
   120
      }
paulwerelds@218
   121
paulwerelds@218
   122
      // TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4
paulwerelds@218
   123
paulwerelds@218
   124
      // For Intel, we make sure we have their 3 most important ID's
paulwerelds@218
   125
      // We do a traditional loop again, because we all we need to know
paulwerelds@218
   126
      // is whether we can find all 3; pointless to use Exists()
paulwerelds@218
   127
      int intelRegisterCount = 0;
paulwerelds@218
   128
      foreach (SMART.DriveAttribute attribute in attributes) {
paulwerelds@233
   129
        if (attribute.ID == SMART.IntelAttributes.HostWrites ||
paulwerelds@233
   130
          attribute.ID == SMART.IntelAttributes.RemainingLife ||
paulwerelds@233
   131
          attribute.ID == SMART.IntelAttributes.MediaWearOutIndicator
paulwerelds@218
   132
        )
paulwerelds@218
   133
          intelRegisterCount++;
paulwerelds@218
   134
      }
paulwerelds@218
   135
paulwerelds@218
   136
      return (intelRegisterCount == 3)
moel@231
   137
        ? SMART.IntelAttributes.RemainingLife
moel@231
   138
        : SMART.AttributeID.None;
paulwerelds@218
   139
    }
paulwerelds@218
   140
paulwerelds@218
   141
    private SMART.AttributeID GetTemperatureIndex(
paulwerelds@233
   142
      SMART.DriveAttribute[] attributes)
paulwerelds@218
   143
    {
paulwerelds@218
   144
      SMART.AttributeID[] validIds = new[] {
moel@231
   145
        SMART.CommonAttributes.Temperature,
moel@231
   146
        SMART.CommonAttributes.DriveTemperature,
moel@231
   147
        SMART.CommonAttributes.AirflowTemperature
paulwerelds@218
   148
      };
paulwerelds@218
   149
paulwerelds@218
   150
      foreach (SMART.AttributeID validId in validIds) {
paulwerelds@218
   151
        SMART.AttributeID id = validId;
paulwerelds@233
   152
        if (Array.Exists(attributes, attr => attr.ID == id))
paulwerelds@218
   153
          return validId;
paulwerelds@218
   154
      }
paulwerelds@218
   155
moel@231
   156
      return SMART.AttributeID.None;
paulwerelds@218
   157
    }
paulwerelds@218
   158
moel@1
   159
    public IHardware[] Hardware {
moel@1
   160
      get {
moel@1
   161
        return hardware.ToArray();
moel@1
   162
      }
moel@1
   163
    }
moel@1
   164
moel@1
   165
    public string GetReport() {
paulwerelds@204
   166
      int p = (int)Environment.OSVersion.Platform;
paulwerelds@204
   167
      if (p == 4 || p == 128) return null;
paulwerelds@204
   168
paulwerelds@204
   169
      StringBuilder r = new StringBuilder();
paulwerelds@204
   170
paulwerelds@204
   171
      r.AppendLine("S.M.A.R.T Data");
paulwerelds@204
   172
      r.AppendLine();
paulwerelds@204
   173
paulwerelds@204
   174
      for (int drive = 0; drive < MAX_DRIVES; drive++) {
paulwerelds@204
   175
        IntPtr handle = SMART.OpenPhysicalDrive(drive);
paulwerelds@204
   176
paulwerelds@204
   177
        if (handle == SMART.INVALID_HANDLE_VALUE)
paulwerelds@204
   178
          continue;
paulwerelds@204
   179
paulwerelds@204
   180
        if (!SMART.EnableSmart(handle, drive)) {
paulwerelds@204
   181
          SMART.CloseHandle(handle);
paulwerelds@204
   182
          continue;
paulwerelds@204
   183
        }
paulwerelds@204
   184
paulwerelds@204
   185
        string name = SMART.ReadName(handle, drive);
paulwerelds@204
   186
        if (name == null) {
paulwerelds@204
   187
          SMART.CloseHandle(handle);
paulwerelds@204
   188
          continue;
paulwerelds@204
   189
        }
paulwerelds@204
   190
paulwerelds@233
   191
        SMART.DriveAttribute[] attributes = SMART.ReadSmart(handle, drive);
paulwerelds@204
   192
paulwerelds@233
   193
        if (attributes.Length > 0) {
paulwerelds@204
   194
          r.AppendLine("Drive name: " + name);
paulwerelds@204
   195
          r.AppendLine();
moel@250
   196
          r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}",
moel@205
   197
            ("ID").PadRight(6),
moel@205
   198
            ("RawValue").PadRight(20),
moel@205
   199
            ("WorstValue").PadRight(12),
moel@205
   200
            ("AttrValue").PadRight(12),
moel@205
   201
            Environment.NewLine);
paulwerelds@204
   202
moel@205
   203
          foreach (SMART.DriveAttribute a in attributes) {
moel@231
   204
            if (a.ID == SMART.AttributeID.None) continue;
moel@205
   205
            string raw = BitConverter.ToString(a.RawValue);
moel@250
   206
            r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}",
moel@205
   207
              a.ID.ToString("d").PadRight(6), 
moel@205
   208
              raw.Replace("-", " ").PadRight(20),
moel@205
   209
              a.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(12),
moel@205
   210
              a.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(12),
moel@205
   211
              Environment.NewLine);
paulwerelds@204
   212
          }
paulwerelds@204
   213
          r.AppendLine();
paulwerelds@204
   214
        }
paulwerelds@204
   215
paulwerelds@204
   216
        SMART.CloseHandle(handle);
paulwerelds@204
   217
      }
paulwerelds@204
   218
paulwerelds@204
   219
      return r.ToString();
moel@1
   220
    }
moel@1
   221
moel@1
   222
    public void Close() {
moel@1
   223
      foreach (HDD hdd in hardware) 
moel@1
   224
        hdd.Close();
moel@1
   225
    }
moel@1
   226
  }
moel@1
   227
}