Fixed Issue 651.
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/.
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>
14 using System.Collections.Generic;
15 using System.Globalization;
18 using OpenHardwareMonitor.Collections;
20 namespace OpenHardwareMonitor.Hardware.HDD {
21 internal abstract class AbstractHarddrive : Hardware {
23 private const int UPDATE_DIVIDER = 30; // update only every 30s
25 // array of all harddrive types, matching type is searched in this order
26 private static Type[] hddTypes = {
33 typeof(GenericHarddisk)
36 private string firmwareRevision;
37 private readonly ISmart smart;
39 private readonly IntPtr handle;
40 private readonly int index;
43 private IList<SmartAttribute> smartAttributes;
44 private IDictionary<SmartAttribute, Sensor> sensors;
46 private DriveInfo[] driveInfos;
47 private Sensor usageSensor;
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)
55 this.firmwareRevision = firmwareRevision;
57 handle = smart.OpenDrive(index);
59 if (handle != smart.InvalidHandle)
60 smart.EnableSmart(handle, index);
65 this.smartAttributes = new List<SmartAttribute>(smartAttributes);
67 string[] logicalDrives = smart.GetLogicalDrives(index);
68 List<DriveInfo> driveInfoList = new List<DriveInfo>(logicalDrives.Length);
69 foreach (string logicalDrive in logicalDrives) {
71 DriveInfo di = new DriveInfo(logicalDrive);
73 driveInfoList.Add(new DriveInfo(logicalDrive));
74 } catch (ArgumentException) {
75 } catch (IOException) {
76 } catch (UnauthorizedAccessException) {
79 driveInfos = driveInfoList.ToArray();
84 public static AbstractHarddrive CreateInstance(ISmart smart,
85 int driveIndex, ISettings settings)
87 IntPtr deviceHandle = smart.OpenDrive(driveIndex);
90 string firmwareRevision = null;
91 DriveAttributeValue[] values = { };
93 if (deviceHandle != smart.InvalidHandle) {
94 bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
95 driveIndex, out name, out firmwareRevision);
96 bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
99 values = smart.ReadSmartData(deviceHandle, driveIndex);
101 smart.CloseHandle(deviceHandle);
105 firmwareRevision = null;
108 string[] logicalDrives = smart.GetLogicalDrives(driveIndex);
109 if (logicalDrives == null || logicalDrives.Length == 0)
112 bool hasNonZeroSizeDrive = false;
113 foreach (string logicalDrive in logicalDrives) {
115 DriveInfo di = new DriveInfo(logicalDrive);
116 if (di.TotalSize > 0) {
117 hasNonZeroSizeDrive = true;
120 } catch (ArgumentException) {
121 } catch (IOException) {
122 } catch (UnauthorizedAccessException) {
126 if (!hasNonZeroSizeDrive)
130 if (string.IsNullOrEmpty(name))
131 name = "Generic Hard Disk";
133 if (string.IsNullOrEmpty(firmwareRevision))
134 firmwareRevision = "Unknown";
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[];
141 // get the array of the required SMART attributes for the current type
142 RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
143 typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
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;
155 if (!adttributeFound) {
156 allRequiredAttributesFound = false;
161 // if an attribute is missing, then try the next type
162 if (!allRequiredAttributesFound)
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;
173 // no matching type has been found
177 private void CreateSensors() {
178 sensors = new Dictionary<SmartAttribute, Sensor>();
180 if (handle != smart.InvalidHandle) {
181 IList<Pair<SensorType, int>> sensorTypeAndChannels =
182 new List<Pair<SensorType, int>>();
184 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
186 foreach (SmartAttribute attribute in smartAttributes) {
187 if (!attribute.SensorType.HasValue)
191 foreach (DriveAttributeValue value in values) {
192 if (value.Identifier == attribute.Identifier) {
200 Pair<SensorType, int> pair = new Pair<SensorType, int>(
201 attribute.SensorType.Value, attribute.SensorChannel);
203 if (!sensorTypeAndChannels.Contains(pair)) {
204 Sensor sensor = new Sensor(attribute.Name,
205 attribute.SensorChannel, attribute.DefaultHiddenSensor,
206 attribute.SensorType.Value, this, attribute.ParameterDescriptions,
209 sensors.Add(attribute, sensor);
210 ActivateSensor(sensor);
211 sensorTypeAndChannels.Add(pair);
216 if (driveInfos.Length > 0) {
218 new Sensor("Used Space", 0, SensorType.Load, this, settings);
219 ActivateSensor(usageSensor);
223 public override HardwareType HardwareType {
224 get { return HardwareType.HDD; }
227 public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
229 public override void Update() {
231 if (handle != smart.InvalidHandle) {
232 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
234 foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors)
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);
245 UpdateAdditionalSensors(values);
248 if (usageSensor != null) {
250 long totalFreeSpace = 0;
252 for (int i = 0; i < driveInfos.Length; i++) {
253 if (!driveInfos[i].IsReady)
256 totalSize += driveInfos[i].TotalSize;
257 totalFreeSpace += driveInfos[i].TotalFreeSpace;
258 } catch (IOException) { } catch (UnauthorizedAccessException) { }
261 usageSensor.Value = 100.0f - (100.0f * totalFreeSpace) / totalSize;
263 usageSensor.Value = null;
269 count %= UPDATE_DIVIDER;
272 public override string GetReport() {
273 StringBuilder r = new StringBuilder();
275 r.AppendLine(this.GetType().Name);
277 r.AppendLine("Drive name: " + name);
278 r.AppendLine("Firmware version: " + firmwareRevision);
281 if (handle != smart.InvalidHandle) {
282 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
283 DriveThresholdValue[] thresholds =
284 smart.ReadSmartThresholds(handle, index);
286 if (values.Length > 0) {
287 r.AppendFormat(CultureInfo.InvariantCulture,
288 " {0}{1}{2}{3}{4}{5}{6}{7}",
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);
298 foreach (DriveAttributeValue value in values) {
299 if (value.Identifier == 0x00)
302 byte? threshold = null;
303 foreach (DriveThresholdValue t in thresholds) {
304 if (t.Identifier == value.Identifier) {
305 threshold = t.Threshold;
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);
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);
339 foreach (DriveInfo di in driveInfos) {
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);
348 } catch (IOException) { } catch (UnauthorizedAccessException) { }
354 protected static float RawToInt(byte[] raw, byte value,
355 IReadOnlyArray<IParameter> parameters)
357 return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
360 public override void Close() {
361 if (handle != smart.InvalidHandle)
362 smart.CloseHandle(handle);
367 public override void Traverse(IVisitor visitor) {
368 foreach (ISensor sensor in Sensors)
369 sensor.Accept(visitor);