Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Mon, 23 Jul 2012 21:54:35 +0000
changeset 370 8e4dedc41924
parent 358 7962499f9cd6
child 374 ea86cea126bc
permissions -rw-r--r--
Added a RAM hardware and sensor, fixed Issue 115.
     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, null, settings);
   173 
   174           sensors.Add(attribute, sensor);
   175           ActivateSensor(sensor);
   176           sensorTypeAndChannels.Add(pair);
   177         }     
   178       }
   179 
   180       if (driveInfos.Length > 0) {
   181         usageSensor = 
   182           new Sensor("Used Space", 0, SensorType.Load, this, settings);
   183         ActivateSensor(usageSensor);
   184       }
   185     }
   186 
   187     public override HardwareType HardwareType {
   188       get { return HardwareType.HDD; }
   189     }
   190 
   191     public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
   192 
   193     public override void Update() {
   194       if (count == 0) {
   195         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   196 
   197         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   198           SmartAttribute attribute = keyValuePair.Key;          
   199           foreach (DriveAttributeValue value in values) {
   200             if (value.Identifier == attribute.Identifier) {
   201               Sensor sensor = keyValuePair.Value;
   202               sensor.Value = attribute.ConvertValue(value);
   203             }
   204           }
   205         }
   206 
   207         UpdateAdditionalSensors(values);
   208 
   209         if (usageSensor != null) {
   210           long totalSize = 0;
   211           long totalFreeSpace = 0;
   212           for (int i = 0; i < driveInfos.Length; i++) {
   213             totalSize += driveInfos[i].TotalSize;
   214             totalFreeSpace += driveInfos[i].TotalFreeSpace;
   215           }
   216           usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
   217         }
   218       }
   219 
   220       count++; 
   221       count %= UPDATE_DIVIDER; 
   222     }
   223 
   224     public override string GetReport() {
   225       StringBuilder r = new StringBuilder();
   226       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   227       DriveThresholdValue[] thresholds = 
   228         smart.ReadSmartThresholds(handle, index);
   229 
   230       if (values.Length > 0) {
   231         r.AppendLine(this.GetType().Name);
   232         r.AppendLine();
   233         r.AppendLine("Drive name: " + name);
   234         r.AppendLine("Firmware version: " + firmwareRevision);
   235         r.AppendLine();    
   236         r.AppendFormat(CultureInfo.InvariantCulture, 
   237           " {0}{1}{2}{3}{4}{5}{6}{7}",
   238           ("ID").PadRight(3),
   239           ("Description").PadRight(35),
   240           ("Raw Value").PadRight(13),
   241           ("Worst").PadRight(6),
   242           ("Value").PadRight(6),
   243           ("Thres").PadRight(6),
   244           ("Physical").PadRight(8),
   245           Environment.NewLine);
   246 
   247         foreach (DriveAttributeValue value in values) {
   248           if (value.Identifier == 0x00) 
   249             break;
   250 
   251           byte? threshold = null;
   252           foreach (DriveThresholdValue t in thresholds) {
   253             if (t.Identifier == value.Identifier) {
   254               threshold = t.Threshold;
   255             }
   256           }
   257 
   258           string description = "Unknown";
   259           float? physical = null;
   260           foreach (SmartAttribute a in smartAttributes) {
   261             if (a.Identifier == value.Identifier) {
   262               description = a.Name;
   263               if (a.HasRawValueConversion | a.SensorType.HasValue)
   264                 physical = a.ConvertValue(value);
   265               else
   266                 physical = null;
   267             }
   268           }
   269 
   270           string raw = BitConverter.ToString(value.RawValue);
   271           r.AppendFormat(CultureInfo.InvariantCulture, 
   272             " {0}{1}{2}{3}{4}{5}{6}{7}",
   273             value.Identifier.ToString("X2").PadRight(3),
   274             description.PadRight(35),
   275             raw.Replace("-", "").PadRight(13),
   276             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   277             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   278             (threshold.HasValue ? threshold.Value.ToString(
   279               CultureInfo.InvariantCulture) : "-").PadRight(6),
   280             (physical.HasValue ? physical.Value.ToString(
   281               CultureInfo.InvariantCulture) : "-").PadRight(8),
   282             Environment.NewLine);
   283         }
   284         r.AppendLine();
   285       }
   286 
   287       foreach (DriveInfo di in driveInfos) {
   288         r.AppendLine("Logical drive name: " + di.Name);
   289         r.AppendLine("Format: " + di.DriveFormat);
   290         r.AppendLine("Total size: " + di.TotalSize);
   291         r.AppendLine("Total free space: " + di.TotalFreeSpace);
   292         r.AppendLine();
   293       }
   294 
   295       return r.ToString();
   296     }
   297 
   298     protected static float RawToInt(byte[] raw, byte value) {
   299       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   300     }
   301 
   302     public override void Close() {
   303       smart.CloseHandle(handle);
   304       base.Close();
   305     }
   306 
   307     public override void Traverse(IVisitor visitor) {
   308       foreach (ISensor sensor in Sensors)
   309         sensor.Accept(visitor);
   310     }
   311   }
   312 }