Hardware/HDD/HDDGroup.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 231 30f5a06f5d8a
child 250 c19d56a0bcad
permissions -rw-r--r--
Fixed a problem, where the MainForm location and size was lost when the application is started minimized and exited without ever showing the form. This caused MainForm_Load to be never called (location and size was not loaded), but the default size and location were still saved. The new implementation only saves the location and size when one of the two is changed.
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@205
   196
          r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
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
            ("Name"),
moel@205
   202
            Environment.NewLine);
paulwerelds@204
   203
moel@205
   204
          foreach (SMART.DriveAttribute a in attributes) {
moel@231
   205
            if (a.ID == SMART.AttributeID.None) continue;
moel@205
   206
            string raw = BitConverter.ToString(a.RawValue);
moel@205
   207
            r.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}{2}{3}{4}{5}",
moel@205
   208
              a.ID.ToString("d").PadRight(6), 
moel@205
   209
              raw.Replace("-", " ").PadRight(20),
moel@205
   210
              a.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(12),
moel@205
   211
              a.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(12),
moel@205
   212
              a.ID,
moel@205
   213
              Environment.NewLine);
paulwerelds@204
   214
          }
paulwerelds@204
   215
          r.AppendLine();
paulwerelds@204
   216
        }
paulwerelds@204
   217
paulwerelds@204
   218
        SMART.CloseHandle(handle);
paulwerelds@204
   219
      }
paulwerelds@204
   220
paulwerelds@204
   221
      return r.ToString();
moel@1
   222
    }
moel@1
   223
moel@1
   224
    public void Close() {
moel@1
   225
      foreach (HDD hdd in hardware) 
moel@1
   226
        hdd.Close();
moel@1
   227
    }
moel@1
   228
  }
moel@1
   229
}