Hardware/HDD/AbstractHarddrive.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 404 1201889d413a
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	Copyright (C) 2010 Paul Werelds
     9   Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
    10 	
    11 */
    12 
    13 using System;
    14 using System.Collections.Generic;
    15 using System.Globalization;
    16 using System.IO;
    17 using System.Text;
    18 using OpenHardwareMonitor.Collections;
    19 
    20 namespace OpenHardwareMonitor.Hardware.HDD {
    21   internal abstract class AbstractHarddrive : Hardware {
    22 
    23     private const int UPDATE_DIVIDER = 30; // update only every 30s
    24 
    25     // array of all harddrive types, matching type is searched in this order
    26     private static Type[] hddTypes = {       
    27       typeof(SSDPlextor),
    28       typeof(SSDIntel),
    29       typeof(SSDSandforce),
    30       typeof(SSDIndilinx),
    31       typeof(SSDSamsung),
    32       typeof(SSDMicron),
    33       typeof(GenericHarddisk)
    34     };
    35 
    36     private string firmwareRevision;
    37     private readonly ISmart smart;
    38 
    39     private readonly IntPtr handle;
    40     private readonly int index;
    41     private int count;
    42 
    43     private IList<SmartAttribute> smartAttributes;
    44     private IDictionary<SmartAttribute, Sensor> sensors;
    45 
    46     private DriveInfo[] driveInfos;
    47     private Sensor usageSensor;
    48 
    49     protected AbstractHarddrive(ISmart smart, string name, 
    50       string firmwareRevision, int index, 
    51       IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
    52       : base(name, new Identifier("hdd",
    53         index.ToString(CultureInfo.InvariantCulture)), settings)
    54     {
    55       this.firmwareRevision = firmwareRevision;
    56       this.smart = smart;
    57       handle = smart.OpenDrive(index);
    58 
    59       if (handle != smart.InvalidHandle)
    60         smart.EnableSmart(handle, index);
    61 
    62       this.index = index;
    63       this.count = 0;
    64 
    65       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    66 
    67       string[] logicalDrives = smart.GetLogicalDrives(index);
    68       List<DriveInfo> driveInfoList = new List<DriveInfo>(logicalDrives.Length);
    69       foreach (string logicalDrive in logicalDrives) {
    70         try {
    71           DriveInfo di = new DriveInfo(logicalDrive);
    72           if (di.TotalSize > 0)
    73             driveInfoList.Add(new DriveInfo(logicalDrive));
    74         } catch (ArgumentException) {
    75         } catch (IOException) {
    76         } catch (UnauthorizedAccessException) {
    77         }
    78       }
    79       driveInfos = driveInfoList.ToArray();
    80 
    81       CreateSensors();
    82     }
    83 
    84     public static AbstractHarddrive CreateInstance(ISmart smart, 
    85       int driveIndex, ISettings settings) 
    86     {
    87       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    88 
    89       string name = null;
    90       string firmwareRevision = null;
    91       DriveAttributeValue[] values = { };
    92 
    93       if (deviceHandle != smart.InvalidHandle) {
    94         bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
    95         driveIndex, out name, out firmwareRevision);
    96         bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
    97 
    98         if (smartEnabled)
    99           values = smart.ReadSmartData(deviceHandle, driveIndex);
   100 
   101         smart.CloseHandle(deviceHandle);
   102 
   103         if (!nameValid) {
   104           name = null;
   105           firmwareRevision = null;
   106         }
   107       } else {
   108         string[] logicalDrives = smart.GetLogicalDrives(driveIndex);
   109         if (logicalDrives == null || logicalDrives.Length == 0)
   110           return null;
   111 
   112         bool hasNonZeroSizeDrive = false;
   113         foreach (string logicalDrive in logicalDrives) {
   114           try {
   115             DriveInfo di = new DriveInfo(logicalDrive);
   116             if (di.TotalSize > 0) {
   117               hasNonZeroSizeDrive = true;
   118               break;
   119             }
   120           } catch (ArgumentException) { 
   121           } catch (IOException) { 
   122           } catch (UnauthorizedAccessException) {
   123           }
   124         }
   125 
   126         if (!hasNonZeroSizeDrive)
   127           return null;
   128       }
   129 
   130       if (string.IsNullOrEmpty(name))
   131         name = "Generic Hard Disk";
   132 
   133       if (string.IsNullOrEmpty(firmwareRevision))
   134         firmwareRevision = "Unknown";
   135 
   136       foreach (Type type in hddTypes) {
   137         // get the array of name prefixes for the current type
   138         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
   139           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
   140 
   141         // get the array of the required SMART attributes for the current type
   142         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
   143           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
   144 
   145         // check if all required attributes are present
   146         bool allRequiredAttributesFound = true;
   147         foreach (var requireAttribute in requiredAttributes) {
   148           bool adttributeFound = false;
   149           foreach (DriveAttributeValue value in values) {
   150             if (value.Identifier == requireAttribute.AttributeId) {
   151               adttributeFound = true;
   152               break;
   153             }
   154           }
   155           if (!adttributeFound) {
   156             allRequiredAttributesFound = false;
   157             break;
   158           }
   159         }
   160 
   161         // if an attribute is missing, then try the next type
   162         if (!allRequiredAttributesFound)
   163           continue;        
   164 
   165         // check if there is a matching name prefix for this type
   166         foreach (NamePrefixAttribute prefix in namePrefixes) {
   167           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   168             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   169               driveIndex, settings) as AbstractHarddrive;
   170         }
   171       }
   172 
   173       // no matching type has been found
   174       return null;
   175     }
   176 
   177     private void CreateSensors() {
   178       sensors = new Dictionary<SmartAttribute, Sensor>();
   179 
   180       if (handle != smart.InvalidHandle) {
   181         IList<Pair<SensorType, int>> sensorTypeAndChannels =
   182           new List<Pair<SensorType, int>>();
   183 
   184         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   185 
   186         foreach (SmartAttribute attribute in smartAttributes) {
   187           if (!attribute.SensorType.HasValue)
   188             continue;
   189 
   190           bool found = false;
   191           foreach (DriveAttributeValue value in values) {
   192             if (value.Identifier == attribute.Identifier) {
   193               found = true;
   194               break;
   195             }
   196           }
   197           if (!found)
   198             continue;
   199 
   200           Pair<SensorType, int> pair = new Pair<SensorType, int>(
   201             attribute.SensorType.Value, attribute.SensorChannel);
   202 
   203           if (!sensorTypeAndChannels.Contains(pair)) {
   204             Sensor sensor = new Sensor(attribute.Name,
   205               attribute.SensorChannel, attribute.DefaultHiddenSensor,
   206               attribute.SensorType.Value, this, attribute.ParameterDescriptions,
   207               settings);
   208 
   209             sensors.Add(attribute, sensor);
   210             ActivateSensor(sensor);
   211             sensorTypeAndChannels.Add(pair);
   212           }
   213         }
   214       }
   215 
   216       if (driveInfos.Length > 0) {
   217         usageSensor = 
   218           new Sensor("Used Space", 0, SensorType.Load, this, settings);
   219         ActivateSensor(usageSensor);
   220       }
   221     }
   222 
   223     public override HardwareType HardwareType {
   224       get { return HardwareType.HDD; }
   225     }
   226 
   227     public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
   228 
   229     public override void Update() {
   230       if (count == 0) {
   231         if (handle != smart.InvalidHandle) {
   232           DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   233 
   234           foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) 
   235           {
   236             SmartAttribute attribute = keyValuePair.Key;
   237             foreach (DriveAttributeValue value in values) {
   238               if (value.Identifier == attribute.Identifier) {
   239                 Sensor sensor = keyValuePair.Value;
   240                 sensor.Value = attribute.ConvertValue(value, sensor.Parameters);
   241               }
   242             }
   243           }
   244 
   245           UpdateAdditionalSensors(values);
   246         }
   247 
   248         if (usageSensor != null) {
   249           long totalSize = 0;
   250           long totalFreeSpace = 0;
   251 
   252           for (int i = 0; i < driveInfos.Length; i++) {
   253             if (!driveInfos[i].IsReady)
   254               continue;
   255             try {
   256               totalSize += driveInfos[i].TotalSize;
   257               totalFreeSpace += driveInfos[i].TotalFreeSpace;
   258             } catch (IOException) { } catch (UnauthorizedAccessException) { }
   259           }
   260           if (totalSize > 0) {
   261             usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
   262           } else {
   263             usageSensor.Value = null;
   264           }
   265         }
   266       }
   267 
   268       count++; 
   269       count %= UPDATE_DIVIDER; 
   270     }
   271 
   272     public override string GetReport() {
   273       StringBuilder r = new StringBuilder();
   274 
   275       r.AppendLine(this.GetType().Name);
   276       r.AppendLine();
   277       r.AppendLine("Drive name: " + name);
   278       r.AppendLine("Firmware version: " + firmwareRevision);
   279       r.AppendLine();
   280 
   281       if (handle != smart.InvalidHandle) {
   282         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   283         DriveThresholdValue[] thresholds =
   284           smart.ReadSmartThresholds(handle, index);
   285 
   286         if (values.Length > 0) {
   287           r.AppendFormat(CultureInfo.InvariantCulture,
   288             " {0}{1}{2}{3}{4}{5}{6}{7}",
   289             ("ID").PadRight(3),
   290             ("Description").PadRight(35),
   291             ("Raw Value").PadRight(13),
   292             ("Worst").PadRight(6),
   293             ("Value").PadRight(6),
   294             ("Thres").PadRight(6),
   295             ("Physical").PadRight(8),
   296             Environment.NewLine);
   297 
   298           foreach (DriveAttributeValue value in values) {
   299             if (value.Identifier == 0x00)
   300               break;
   301 
   302             byte? threshold = null;
   303             foreach (DriveThresholdValue t in thresholds) {
   304               if (t.Identifier == value.Identifier) {
   305                 threshold = t.Threshold;
   306               }
   307             }
   308 
   309             string description = "Unknown";
   310             float? physical = null;
   311             foreach (SmartAttribute a in smartAttributes) {
   312               if (a.Identifier == value.Identifier) {
   313                 description = a.Name;
   314                 if (a.HasRawValueConversion | a.SensorType.HasValue)
   315                   physical = a.ConvertValue(value, null);
   316                 else
   317                   physical = null;
   318               }
   319             }
   320 
   321             string raw = BitConverter.ToString(value.RawValue);
   322             r.AppendFormat(CultureInfo.InvariantCulture,
   323               " {0}{1}{2}{3}{4}{5}{6}{7}",
   324               value.Identifier.ToString("X2").PadRight(3),
   325               description.PadRight(35),
   326               raw.Replace("-", "").PadRight(13),
   327               value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   328               value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   329               (threshold.HasValue ? threshold.Value.ToString(
   330                 CultureInfo.InvariantCulture) : "-").PadRight(6),
   331               (physical.HasValue ? physical.Value.ToString(
   332                 CultureInfo.InvariantCulture) : "-").PadRight(8),
   333               Environment.NewLine);
   334           }
   335           r.AppendLine();
   336         }
   337       }
   338 
   339       foreach (DriveInfo di in driveInfos) {
   340         if (!di.IsReady)
   341           continue;
   342         try {
   343           r.AppendLine("Logical drive name: " + di.Name);
   344           r.AppendLine("Format: " + di.DriveFormat);
   345           r.AppendLine("Total size: " + di.TotalSize);
   346           r.AppendLine("Total free space: " + di.TotalFreeSpace);
   347           r.AppendLine();
   348         } catch (IOException) { } catch (UnauthorizedAccessException) { }
   349       }
   350 
   351       return r.ToString();
   352     }
   353 
   354     protected static float RawToInt(byte[] raw, byte value,
   355       IReadOnlyArray<IParameter> parameters) 
   356     {
   357       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   358     }
   359 
   360     public override void Close() {
   361       if (handle != smart.InvalidHandle)
   362         smart.CloseHandle(handle);
   363 
   364       base.Close();
   365     }
   366 
   367     public override void Traverse(IVisitor visitor) {
   368       foreach (ISensor sensor in Sensors)
   369         sensor.Accept(visitor);
   370     }
   371   }
   372 }