Added SMART support for Samsung SSDs.
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 = {
58 typeof(GenericHarddisk)
61 private string firmwareRevision;
62 private readonly ISmart smart;
64 private readonly IntPtr handle;
65 private readonly int index;
68 private IList<SmartAttribute> smartAttributes;
69 private IDictionary<SmartAttribute, Sensor> sensors;
71 protected AbstractHarddrive(ISmart smart, string name,
72 string firmwareRevision, int index,
73 IEnumerable<SmartAttribute> smartAttributes, ISettings settings)
74 : base(name, new Identifier("hdd",
75 index.ToString(CultureInfo.InvariantCulture)), settings)
77 this.firmwareRevision = firmwareRevision;
79 handle = smart.OpenDrive(index);
81 smart.EnableSmart(handle, index);
86 this.smartAttributes = new List<SmartAttribute>(smartAttributes);
91 public static AbstractHarddrive CreateInstance(ISmart smart,
92 int driveIndex, ISettings settings)
94 IntPtr deviceHandle = smart.OpenDrive(driveIndex);
96 if (deviceHandle == smart.InvalidHandle)
100 string firmwareRevision;
101 bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle,
102 driveIndex, out name, out firmwareRevision);
103 bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
105 DriveAttributeValue[] values = {};
107 values = smart.ReadSmartData(deviceHandle, driveIndex);
109 smart.CloseHandle(deviceHandle);
111 if (!nameValid || string.IsNullOrEmpty(name))
114 foreach (Type type in hddTypes) {
115 // get the array of name prefixes for the current type
116 NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
117 typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
119 // get the array of the required SMART attributes for the current type
120 RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
121 typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
123 // check if all required attributes are present
124 bool allRequiredAttributesFound = true;
125 foreach (var requireAttribute in requiredAttributes) {
126 bool adttributeFound = false;
127 foreach (DriveAttributeValue value in values) {
128 if (value.Identifier == requireAttribute.AttributeId) {
129 adttributeFound = true;
133 if (!adttributeFound) {
134 allRequiredAttributesFound = false;
139 // if an attribute is missing, then try the next type
140 if (!allRequiredAttributesFound)
143 // check if there is a matching name prefix for this type
144 foreach (NamePrefixAttribute prefix in namePrefixes) {
145 if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture))
146 return Activator.CreateInstance(type, smart, name, firmwareRevision,
147 driveIndex, settings) as AbstractHarddrive;
151 // no matching type has been found
155 private void CreateSensors() {
156 sensors = new Dictionary<SmartAttribute, Sensor>();
158 IList<Pair<SensorType, int>> sensorTypeAndChannels =
159 new List<Pair<SensorType, int>>();
161 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
163 foreach (SmartAttribute attribute in smartAttributes) {
164 if (!attribute.SensorType.HasValue)
168 foreach (DriveAttributeValue value in values) {
169 if (value.Identifier == attribute.Identifier) {
177 Pair<SensorType, int> pair = new Pair<SensorType, int>(
178 attribute.SensorType.Value, attribute.SensorChannel);
180 if (!sensorTypeAndChannels.Contains(pair)) {
181 Sensor sensor = new Sensor(attribute.Name,
182 attribute.SensorChannel, attribute.SensorType.Value, this,
185 sensors.Add(attribute, sensor);
186 sensorTypeAndChannels.Add(pair);
191 public override HardwareType HardwareType {
192 get { return HardwareType.HDD; }
195 public override ISensor[] Sensors {
197 Sensor[] array = new Sensor[sensors.Count];
198 sensors.Values.CopyTo(array, 0);
203 public override void Update() {
205 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
207 foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
208 SmartAttribute attribute = keyValuePair.Key;
209 foreach (DriveAttributeValue value in values) {
210 if (value.Identifier == attribute.Identifier) {
211 Sensor sensor = keyValuePair.Value;
212 sensor.Value = attribute.ConvertValue(value);
219 count %= UPDATE_DIVIDER;
222 public override string GetReport() {
223 StringBuilder r = new StringBuilder();
224 DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
225 DriveThresholdValue[] thresholds =
226 smart.ReadSmartThresholds(handle, index);
228 if (values.Length > 0) {
229 r.AppendLine(this.GetType().Name);
231 r.AppendLine("Drive name: " + name);
232 r.AppendLine("Firmware version: " + firmwareRevision);
234 r.AppendFormat(CultureInfo.InvariantCulture,
235 " {0}{1}{2}{3}{4}{5}{6}{7}",
237 ("Description").PadRight(35),
238 ("Raw Value").PadRight(13),
239 ("Worst").PadRight(6),
240 ("Value").PadRight(6),
241 ("Thres").PadRight(6),
242 ("Physical").PadRight(8),
243 Environment.NewLine);
245 foreach (DriveAttributeValue value in values) {
246 if (value.Identifier == 0x00)
249 byte? threshold = null;
250 foreach (DriveThresholdValue t in thresholds) {
251 if (t.Identifier == value.Identifier) {
252 threshold = t.Threshold;
256 string description = "Unknown";
257 float? physical = null;
258 foreach (SmartAttribute a in smartAttributes) {
259 if (a.Identifier == value.Identifier) {
260 description = a.Name;
261 if (a.HasRawValueConversion | a.SensorType.HasValue)
262 physical = a.ConvertValue(value);
268 string raw = BitConverter.ToString(value.RawValue);
269 r.AppendFormat(CultureInfo.InvariantCulture,
270 " {0}{1}{2}{3}{4}{5}{6}{7}",
271 value.Identifier.ToString("X2").PadRight(3),
272 description.PadRight(35),
273 raw.Replace("-", "").PadRight(13),
274 value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
275 value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
276 (threshold.HasValue ? threshold.Value.ToString(
277 CultureInfo.InvariantCulture) : "-").PadRight(6),
278 (physical.HasValue ? physical.Value.ToString(
279 CultureInfo.InvariantCulture) : "-").PadRight(8),
280 Environment.NewLine);
288 protected static float RawToInt(byte[] raw, byte value) {
289 return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
292 public override void Close() {
293 smart.CloseHandle(handle);
297 public override void Traverse(IVisitor visitor) {
298 foreach (ISensor sensor in Sensors)
299 sensor.Accept(visitor);