Hardware/HDD/HDDGroup.cs
author paulwerelds
Fri, 08 Oct 2010 12:18:32 +0000
changeset 218 194186efdde9
parent 205 a38b51ef489c
child 231 30f5a06f5d8a
permissions -rw-r--r--
Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
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@218
    71
        List<SMART.DriveAttribute> attributes =
paulwerelds@218
    72
          new List<SMART.DriveAttribute>(SMART.ReadSmart(handle, drive));
paulwerelds@218
    73
        
paulwerelds@218
    74
        if (!(attributes.Count > 0)) {
moel@205
    75
          SMART.CloseHandle(handle);
moel@205
    76
          continue;
moel@205
    77
        }
paulwerelds@204
    78
paulwerelds@218
    79
        SMART.SSDLifeID ssdLifeID = GetSSDLifeID(attributes);
paulwerelds@218
    80
        if (ssdLifeID == SMART.SSDLifeID.None) {
paulwerelds@218
    81
          SMART.AttributeID temperatureID = GetTemperatureIndex(attributes);
paulwerelds@204
    82
paulwerelds@218
    83
          if (temperatureID != 0x00) {
paulwerelds@218
    84
            hardware.Add(new HDD(name, handle, drive, temperatureID, settings));
paulwerelds@218
    85
            continue;
moel@205
    86
          }
paulwerelds@218
    87
        } else {
paulwerelds@218
    88
          hardware.Add(new HDD(name, handle, drive, ssdLifeID, settings));
moel@205
    89
          continue;
paulwerelds@204
    90
        }
paulwerelds@218
    91
        
paulwerelds@204
    92
        SMART.CloseHandle(handle);
moel@1
    93
      }
moel@1
    94
    }
moel@1
    95
paulwerelds@218
    96
    private SMART.SSDLifeID GetSSDLifeID(List<SMART.DriveAttribute> attributes) {
paulwerelds@218
    97
      // ID E9 is present on Intel, JM, SF and Samsung
paulwerelds@218
    98
      // ID D2 is present on Indilinx
paulwerelds@218
    99
      // Neither ID has been found on a mechanical hard drive (yet),
paulwerelds@218
   100
      // So this seems like a good way to check if it's an SSD.
paulwerelds@218
   101
      bool isKnownSSD = (attributes.Exists(attr => (int)attr.ID == 0xE9) ||
paulwerelds@218
   102
              attributes.Exists(attr => (int)attr.ID == 0xD2)
paulwerelds@218
   103
      );
paulwerelds@218
   104
paulwerelds@218
   105
      if (!isKnownSSD) return SMART.SSDLifeID.None;
paulwerelds@218
   106
paulwerelds@218
   107
      // We start with a traditional loop, because there are 4 unique ID's
paulwerelds@218
   108
      // that potentially identify one of the vendors
paulwerelds@218
   109
      for (int i = 0; i < attributes.Count; i++) {
paulwerelds@218
   110
paulwerelds@218
   111
        switch ((int)attributes[i].ID) {
paulwerelds@218
   112
          case 0xB4:
paulwerelds@218
   113
            return SMART.SSDLifeID.Samsung;
paulwerelds@218
   114
          case 0xAB:
paulwerelds@218
   115
            return SMART.SSDLifeID.SandForce;
paulwerelds@218
   116
          case 0xD2:
paulwerelds@218
   117
            return SMART.SSDLifeID.Indilinx;
paulwerelds@218
   118
        }
paulwerelds@218
   119
      }
paulwerelds@218
   120
paulwerelds@218
   121
      // TODO: Find out JMicron's Life attribute ID; their unique ID = 0xE4
paulwerelds@218
   122
paulwerelds@218
   123
      // For Intel, we make sure we have their 3 most important ID's
paulwerelds@218
   124
      // We do a traditional loop again, because we all we need to know
paulwerelds@218
   125
      // is whether we can find all 3; pointless to use Exists()
paulwerelds@218
   126
      int intelRegisterCount = 0;
paulwerelds@218
   127
      foreach (SMART.DriveAttribute attribute in attributes) {
paulwerelds@218
   128
        if ((int)attribute.ID == 0xE1 ||
paulwerelds@218
   129
          (int)attribute.ID == 0xE8 ||
paulwerelds@218
   130
          (int)attribute.ID == 0xE9
paulwerelds@218
   131
        )
paulwerelds@218
   132
          intelRegisterCount++;
paulwerelds@218
   133
      }
paulwerelds@218
   134
paulwerelds@218
   135
      return (intelRegisterCount == 3)
paulwerelds@218
   136
        ? SMART.SSDLifeID.Intel
paulwerelds@218
   137
        : SMART.SSDLifeID.None;
paulwerelds@218
   138
    }
paulwerelds@218
   139
paulwerelds@218
   140
    private SMART.AttributeID GetTemperatureIndex(
paulwerelds@218
   141
      List<SMART.DriveAttribute> attributes)
paulwerelds@218
   142
    {
paulwerelds@218
   143
      SMART.AttributeID[] validIds = new[] {
paulwerelds@218
   144
        SMART.AttributeID.Temperature,
paulwerelds@218
   145
        SMART.AttributeID.DriveTemperature,
paulwerelds@218
   146
        SMART.AttributeID.AirflowTemperature
paulwerelds@218
   147
      };
paulwerelds@218
   148
paulwerelds@218
   149
      foreach (SMART.AttributeID validId in validIds) {
paulwerelds@218
   150
        SMART.AttributeID id = validId;
paulwerelds@218
   151
        if (attributes.Exists(attr => attr.ID == id))
paulwerelds@218
   152
          return validId;
paulwerelds@218
   153
      }
paulwerelds@218
   154
paulwerelds@218
   155
      return 0x00;
paulwerelds@218
   156
    }
paulwerelds@218
   157
moel@1
   158
    public IHardware[] Hardware {
moel@1
   159
      get {
moel@1
   160
        return hardware.ToArray();
moel@1
   161
      }
moel@1
   162
    }
moel@1
   163
moel@1
   164
    public string GetReport() {
paulwerelds@204
   165
      int p = (int)Environment.OSVersion.Platform;
paulwerelds@204
   166
      if (p == 4 || p == 128) return null;
paulwerelds@204
   167
paulwerelds@204
   168
      StringBuilder r = new StringBuilder();
paulwerelds@204
   169
paulwerelds@204
   170
      r.AppendLine("S.M.A.R.T Data");
paulwerelds@204
   171
      r.AppendLine();
paulwerelds@204
   172
paulwerelds@204
   173
      for (int drive = 0; drive < MAX_DRIVES; drive++) {
paulwerelds@204
   174
        IntPtr handle = SMART.OpenPhysicalDrive(drive);
paulwerelds@204
   175
paulwerelds@204
   176
        if (handle == SMART.INVALID_HANDLE_VALUE)
paulwerelds@204
   177
          continue;
paulwerelds@204
   178
paulwerelds@204
   179
        if (!SMART.EnableSmart(handle, drive)) {
paulwerelds@204
   180
          SMART.CloseHandle(handle);
paulwerelds@204
   181
          continue;
paulwerelds@204
   182
        }
paulwerelds@204
   183
paulwerelds@204
   184
        string name = SMART.ReadName(handle, drive);
paulwerelds@204
   185
        if (name == null) {
paulwerelds@204
   186
          SMART.CloseHandle(handle);
paulwerelds@204
   187
          continue;
paulwerelds@204
   188
        }
paulwerelds@204
   189
paulwerelds@218
   190
        List<SMART.DriveAttribute> attributes = SMART.ReadSmart(handle, drive);
paulwerelds@204
   191
paulwerelds@204
   192
        if (attributes != null) {
paulwerelds@204
   193
          r.AppendLine("Drive name: " + name);
paulwerelds@204
   194
          r.AppendLine();
moel@205
   195
          r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
moel@205
   196
            ("ID").PadRight(6),
moel@205
   197
            ("RawValue").PadRight(20),
moel@205
   198
            ("WorstValue").PadRight(12),
moel@205
   199
            ("AttrValue").PadRight(12),
moel@205
   200
            ("Name"),
moel@205
   201
            Environment.NewLine);
paulwerelds@204
   202
moel@205
   203
          foreach (SMART.DriveAttribute a in attributes) {
moel@205
   204
            if (a.ID == 0) continue;
moel@205
   205
            string raw = BitConverter.ToString(a.RawValue);
moel@205
   206
            r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
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
              a.ID,
moel@205
   212
              Environment.NewLine);
paulwerelds@204
   213
          }
paulwerelds@204
   214
          r.AppendLine();
paulwerelds@204
   215
        }
paulwerelds@204
   216
paulwerelds@204
   217
        SMART.CloseHandle(handle);
paulwerelds@204
   218
      }
paulwerelds@204
   219
paulwerelds@204
   220
      return r.ToString();
moel@1
   221
    }
moel@1
   222
moel@1
   223
    public void Close() {
moel@1
   224
      foreach (HDD hdd in hardware) 
moel@1
   225
        hdd.Close();
moel@1
   226
    }
moel@1
   227
  }
moel@1
   228
}