Added the hard drive firmware version to the report. This could be important if the SMART attribute layout changes with firmware versions on some drives.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2012
20 the Initial Developer. All Rights Reserved.
24 Roland Reinl <roland-reinl@gmx.de>
26 Alternatively, the contents of this file may be used under the terms of
27 either the GNU General Public License Version 2 or later (the "GPL"), or
28 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 in which case the provisions of the GPL or the LGPL are applicable instead
30 of those above. If you wish to allow use of your version of this file only
31 under the terms of either the GPL or the LGPL, and not to allow others to
32 use your version of this file under the terms of the MPL, indicate your
33 decision by deleting the provisions above and replace them with the notice
34 and other provisions required by the GPL or the LGPL. If you do not delete
35 the provisions above, a recipient may use your version of this file under
36 the terms of any one of the MPL, the GPL or the LGPL.
41 using System.Collections.Generic;
42 using System.Globalization;
44 using OpenHardwareMonitor.Collections;
46 namespace OpenHardwareMonitor.Hardware.HDD {
47 internal abstract class AbstractHarddrive : Hardware {
49 private const int UPDATE_DIVIDER = 30; // update only every 30s
51 // array of all harddrive types, matching type is searched in this order
52 private static Type[] hddTypes = {
57 typeof(GenericHarddisk)
60 private string firmwareRevision;
61 private readonly ISmart smart;
63 private readonly IntPtr handle;
64 private readonly int index;
67 private IList<SmartAttribute> smartAttributes;
68 private IDictionary<SmartAttribute, Sensor> sensors;
70 protected AbstractHarddrive(ISmart smart, string name,
71 string firmwareRevision, int index,
72 IEnumerable<SmartAttribute> smartAttributes, ISettings settings)
73 : base(name, new Identifier("hdd",
74 index.ToString(CultureInfo.InvariantCulture)), settings)
76 this.firmwareRevision = firmwareRevision;
78 handle = smart.OpenDrive(index);
80 smart.EnableSmart(handle, index);
85 this.smartAttributes = new List<SmartAttribute>(smartAttributes);
90 public static AbstractHarddrive CreateInstance(ISmart smart,
91 int driveIndex, ISettings settings)
93 IntPtr deviceHandle = smart.OpenDrive(driveIndex);
95 if (deviceHandle == smart.InvalidHandle)
99 string firmwareRevision;
100 bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
101 driveIndex, out name, out firmwareRevision);
102 bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
104 DriveAttributeValue[] values = {};
106 values = smart.ReadSmartData(deviceHandle, driveIndex);
108 smart.CloseHandle(deviceHandle);
110 if (!nameValid || string.IsNullOrEmpty(name))
113 foreach (Type type in hddTypes) {
114 // get the array of name prefixes for the current type
115 NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
116 typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
118 // get the array of the required SMART attributes for the current type
119 RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
120 typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
122 // check if all required attributes are present
123 bool allRequiredAttributesFound = true;
124 foreach (var requireAttribute in requiredAttributes) {
125 bool adttributeFound = false;
126 foreach (DriveAttributeValue value in values) {
127 if (value.Identifier == requireAttribute.AttributeId) {
128 adttributeFound = true;
132 if (!adttributeFound) {
133 allRequiredAttributesFound = false;
138 // if an attribute is missing, then try the next type
139 if (!allRequiredAttributesFound)
142 // check if there is a matching name prefix for this type
143 foreach (NamePrefixAttribute prefix in namePrefixes) {
144 if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture))
145 return Activator.CreateInstance(type, smart, name, firmwareRevision,
146 driveIndex, settings) as AbstractHarddrive;
150 // no matching type has been found
154 private void CreateSensors() {
155 sensors = new Dictionary<SmartAttribute, Sensor>();
157 IList<Pair<SensorType, int>> sensorTypeAndChannels =
158 new List<Pair<SensorType, int>>();
160 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
162 foreach (SmartAttribute attribute in smartAttributes) {
163 if (!attribute.SensorType.HasValue)
167 foreach (DriveAttributeValue value in values) {
168 if (value.Identifier == attribute.Identifier) {
176 Pair<SensorType, int> pair = new Pair<SensorType, int>(
177 attribute.SensorType.Value, attribute.SensorChannel);
179 if (!sensorTypeAndChannels.Contains(pair)) {
180 Sensor sensor = new Sensor(attribute.Name,
181 attribute.SensorChannel, attribute.SensorType.Value, this,
184 sensors.Add(attribute, sensor);
185 sensorTypeAndChannels.Add(pair);
190 public override HardwareType HardwareType {
191 get { return HardwareType.HDD; }
194 public override ISensor[] Sensors {
196 Sensor[] array = new Sensor[sensors.Count];
197 sensors.Values.CopyTo(array, 0);
202 public override void Update() {
204 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
206 foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
207 SmartAttribute attribute = keyValuePair.Key;
208 foreach (DriveAttributeValue value in values) {
209 if (value.Identifier == attribute.Identifier) {
210 Sensor sensor = keyValuePair.Value;
211 sensor.Value = attribute.ConvertValue(value);
218 count %= UPDATE_DIVIDER;
221 public override string GetReport() {
222 StringBuilder r = new StringBuilder();
223 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
224 DriveThresholdValue[] thresholds =
225 smart.ReadSmartThresholds(handle, index);
227 if (values.Length > 0) {
228 r.AppendLine(this.GetType().Name);
230 r.AppendLine("Drive name: " + name);
231 r.AppendLine("Firmware version: " + firmwareRevision);
233 r.AppendFormat(CultureInfo.InvariantCulture,
234 " {0}{1}{2}{3}{4}{5}{6}{7}",
236 ("Description").PadRight(32),
237 ("Raw Value").PadRight(13),
238 ("Worst").PadRight(6),
239 ("Value").PadRight(6),
240 ("Thres").PadRight(6),
241 ("Physical").PadRight(8),
242 Environment.NewLine);
244 foreach (DriveAttributeValue value in values) {
245 if (value.Identifier == 0x00)
248 byte? threshold = null;
249 foreach (DriveThresholdValue t in thresholds) {
250 if (t.Identifier == value.Identifier) {
251 threshold = t.Threshold;
255 string description = "Unknown";
256 float? physical = null;
257 foreach (SmartAttribute a in smartAttributes) {
258 if (a.Identifier == value.Identifier) {
259 description = a.Name;
260 if (a.HasRawValueConversion | a.SensorType.HasValue)
261 physical = a.ConvertValue(value);
267 string raw = BitConverter.ToString(value.RawValue);
268 r.AppendFormat(CultureInfo.InvariantCulture,
269 " {0}{1}{2}{3}{4}{5}{6}{7}",
270 value.Identifier.ToString("X2").PadRight(3),
271 description.PadRight(32),
272 raw.Replace("-", "").PadRight(13),
273 value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
274 value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
275 (threshold.HasValue ? threshold.Value.ToString(
276 CultureInfo.InvariantCulture) : "-").PadRight(6),
277 (physical.HasValue ? physical.Value.ToString(
278 CultureInfo.InvariantCulture) : "-").PadRight(8),
279 Environment.NewLine);
287 protected static float RawToInt(byte[] raw, byte value) {
288 return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
291 public override void Close() {
292 smart.CloseHandle(handle);
296 public override void Traverse(IVisitor visitor) {
297 foreach (ISensor sensor in Sensors)
298 sensor.Accept(visitor);