Hardware/HDD/AbstractHarddrive.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
changeset 402 ded1323b61ee
parent 374 ea86cea126bc
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-2012 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       smart.EnableSmart(handle, index);
    60 
    61       this.index = index;
    62       this.count = 0;
    63 
    64       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    65 
    66       string[] logicalDrives = smart.GetLogicalDrives(index);
    67       List<DriveInfo> driveInfoList = new List<DriveInfo>(logicalDrives.Length);
    68       foreach (string logicalDrive in logicalDrives) {
    69         try {
    70           DriveInfo di = new DriveInfo(logicalDrive);
    71           if (di.TotalSize > 0) 
    72             driveInfoList.Add(new DriveInfo(logicalDrive));
    73         } catch (ArgumentException) { } catch (IOException) { }
    74       }
    75       driveInfos = driveInfoList.ToArray();
    76 
    77       CreateSensors();
    78     }
    79 
    80     public static AbstractHarddrive CreateInstance(ISmart smart, 
    81       int driveIndex, ISettings settings) 
    82     {
    83       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    84 
    85       if (deviceHandle == smart.InvalidHandle) 
    86         return null;
    87 
    88       string name;
    89       string firmwareRevision;
    90       bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
    91         driveIndex, out name, out firmwareRevision);
    92       bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
    93 
    94       DriveAttributeValue[] values = {};
    95       if (smartEnabled)
    96         values = smart.ReadSmartData(deviceHandle, driveIndex);
    97 
    98       smart.CloseHandle(deviceHandle);
    99 
   100       if (!nameValid || string.IsNullOrEmpty(name)) 
   101         return null;      
   102 
   103       foreach (Type type in hddTypes) {
   104         // get the array of name prefixes for the current type
   105         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
   106           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
   107 
   108         // get the array of the required SMART attributes for the current type
   109         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
   110           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
   111 
   112         // check if all required attributes are present
   113         bool allRequiredAttributesFound = true;
   114         foreach (var requireAttribute in requiredAttributes) {
   115           bool adttributeFound = false;
   116           foreach (DriveAttributeValue value in values) {
   117             if (value.Identifier == requireAttribute.AttributeId) {
   118               adttributeFound = true;
   119               break;
   120             }
   121           }
   122           if (!adttributeFound) {
   123             allRequiredAttributesFound = false;
   124             break;
   125           }
   126         }
   127 
   128         // if an attribute is missing, then try the next type
   129         if (!allRequiredAttributesFound)
   130           continue;        
   131 
   132         // check if there is a matching name prefix for this type
   133         foreach (NamePrefixAttribute prefix in namePrefixes) {
   134           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   135             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   136               driveIndex, settings) as AbstractHarddrive;
   137         }
   138       }
   139 
   140       // no matching type has been found
   141       return null;
   142     }
   143 
   144     private void CreateSensors() {
   145       sensors = new Dictionary<SmartAttribute, Sensor>();
   146 
   147       IList<Pair<SensorType, int>> sensorTypeAndChannels = 
   148         new List<Pair<SensorType, int>>();
   149 
   150       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   151 
   152       foreach (SmartAttribute attribute in smartAttributes) {
   153         if (!attribute.SensorType.HasValue) 
   154           continue;
   155 
   156         bool found = false;
   157         foreach (DriveAttributeValue value in values) {
   158           if (value.Identifier == attribute.Identifier) {
   159             found = true;
   160             break;
   161           }
   162         }
   163         if (!found)
   164           continue;
   165 
   166         Pair<SensorType, int> pair = new Pair<SensorType, int>(
   167           attribute.SensorType.Value, attribute.SensorChannel);
   168 
   169         if (!sensorTypeAndChannels.Contains(pair)) {
   170           Sensor sensor = new Sensor(attribute.Name, 
   171             attribute.SensorChannel, attribute.DefaultHiddenSensor, 
   172             attribute.SensorType.Value, this, attribute.ParameterDescriptions, 
   173             settings);
   174 
   175           sensors.Add(attribute, sensor);
   176           ActivateSensor(sensor);
   177           sensorTypeAndChannels.Add(pair);
   178         }     
   179       }
   180 
   181       if (driveInfos.Length > 0) {
   182         usageSensor = 
   183           new Sensor("Used Space", 0, SensorType.Load, this, settings);
   184         ActivateSensor(usageSensor);
   185       }
   186     }
   187 
   188     public override HardwareType HardwareType {
   189       get { return HardwareType.HDD; }
   190     }
   191 
   192     public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
   193 
   194     public override void Update() {
   195       if (count == 0) {
   196         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   197 
   198         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   199           SmartAttribute attribute = keyValuePair.Key;
   200           foreach (DriveAttributeValue value in values) {
   201             if (value.Identifier == attribute.Identifier) {
   202               Sensor sensor = keyValuePair.Value;
   203               sensor.Value = attribute.ConvertValue(value, sensor.Parameters);
   204             }
   205           }
   206         }
   207 
   208         UpdateAdditionalSensors(values);
   209 
   210         if (usageSensor != null) {
   211           long totalSize = 0;
   212           long totalFreeSpace = 0;
   213 
   214           for (int i = 0; i < driveInfos.Length; i++) {
   215             if (!driveInfos[i].IsReady)
   216               continue;
   217             try {
   218               totalSize += driveInfos[i].TotalSize;
   219               totalFreeSpace += driveInfos[i].TotalFreeSpace;
   220             } catch (IOException) { } catch (UnauthorizedAccessException) { }
   221           }
   222           if (totalSize > 0) {
   223             usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
   224           } else {
   225             usageSensor.Value = null;
   226           }
   227         }
   228       }
   229 
   230       count++; 
   231       count %= UPDATE_DIVIDER; 
   232     }
   233 
   234     public override string GetReport() {
   235       StringBuilder r = new StringBuilder();
   236       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   237       DriveThresholdValue[] thresholds = 
   238         smart.ReadSmartThresholds(handle, index);
   239 
   240       if (values.Length > 0) {
   241         r.AppendLine(this.GetType().Name);
   242         r.AppendLine();
   243         r.AppendLine("Drive name: " + name);
   244         r.AppendLine("Firmware version: " + firmwareRevision);
   245         r.AppendLine();    
   246         r.AppendFormat(CultureInfo.InvariantCulture, 
   247           " {0}{1}{2}{3}{4}{5}{6}{7}",
   248           ("ID").PadRight(3),
   249           ("Description").PadRight(35),
   250           ("Raw Value").PadRight(13),
   251           ("Worst").PadRight(6),
   252           ("Value").PadRight(6),
   253           ("Thres").PadRight(6),
   254           ("Physical").PadRight(8),
   255           Environment.NewLine);
   256 
   257         foreach (DriveAttributeValue value in values) {
   258           if (value.Identifier == 0x00) 
   259             break;
   260 
   261           byte? threshold = null;
   262           foreach (DriveThresholdValue t in thresholds) {
   263             if (t.Identifier == value.Identifier) {
   264               threshold = t.Threshold;
   265             }
   266           }
   267 
   268           string description = "Unknown";
   269           float? physical = null;
   270           foreach (SmartAttribute a in smartAttributes) {
   271             if (a.Identifier == value.Identifier) {
   272               description = a.Name;
   273               if (a.HasRawValueConversion | a.SensorType.HasValue)
   274                 physical = a.ConvertValue(value, null);
   275               else
   276                 physical = null;
   277             }
   278           }
   279 
   280           string raw = BitConverter.ToString(value.RawValue);
   281           r.AppendFormat(CultureInfo.InvariantCulture, 
   282             " {0}{1}{2}{3}{4}{5}{6}{7}",
   283             value.Identifier.ToString("X2").PadRight(3),
   284             description.PadRight(35),
   285             raw.Replace("-", "").PadRight(13),
   286             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   287             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   288             (threshold.HasValue ? threshold.Value.ToString(
   289               CultureInfo.InvariantCulture) : "-").PadRight(6),
   290             (physical.HasValue ? physical.Value.ToString(
   291               CultureInfo.InvariantCulture) : "-").PadRight(8),
   292             Environment.NewLine);
   293         }
   294         r.AppendLine();
   295       }
   296 
   297       foreach (DriveInfo di in driveInfos) {
   298         r.AppendLine("Logical drive name: " + di.Name);
   299         r.AppendLine("Format: " + di.DriveFormat);
   300         r.AppendLine("Total size: " + di.TotalSize);
   301         r.AppendLine("Total free space: " + di.TotalFreeSpace);
   302         r.AppendLine();
   303       }
   304 
   305       return r.ToString();
   306     }
   307 
   308     protected static float RawToInt(byte[] raw, byte value,
   309       IReadOnlyArray<IParameter> parameters) 
   310     {
   311       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   312     }
   313 
   314     public override void Close() {
   315       smart.CloseHandle(handle);
   316       base.Close();
   317     }
   318 
   319     public override void Traverse(IVisitor visitor) {
   320       foreach (ISensor sensor in Sensors)
   321         sensor.Accept(visitor);
   322     }
   323   }
   324 }