Added thermal and voltage/frequency MSRs for K8 CPUs, fixed chars-per-line limit
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) 2010
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Globalization;
41 using System.IO.Ports;
43 using System.Text.RegularExpressions;
44 using System.Threading;
46 namespace OpenHardwareMonitor.Hardware.Heatmaster {
47 internal class Heatmaster : Hardware, IDisposable {
49 private string portName;
50 private SerialPort serialPort;
52 private int hardwareRevision;
53 private int firmwareRevision;
54 private int firmwareCRC;
56 private Sensor[] fans;
57 private Sensor[] controls;
58 private Sensor[] temperatures;
59 private Sensor[] flows;
60 private Sensor[] relays;
62 private bool available = false;
64 private StringBuilder buffer = new StringBuilder();
66 private string ReadLine(int timeout) {
68 StringBuilder builder = new StringBuilder();
69 while (i <= timeout) {
70 while (serialPort.BytesToRead > 0) {
71 byte b = (byte)serialPort.ReadByte();
73 case 0xAA: return ((char)b).ToString();
74 case 0x0D: return builder.ToString();
75 default: builder.Append((char)b); break;
81 throw new TimeoutException();
84 private string ReadField(int device, char field) {
85 serialPort.WriteLine("[0:" + device + "]R" + field);
86 for (int i = 0; i < 5; i++) {
87 string s = ReadLine(200);
88 Match match = Regex.Match(s, @"-\[0:" +
89 device.ToString(CultureInfo.InvariantCulture) + @"\]R" +
90 Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":(.*)");
92 return match.Groups[1].Value;
97 private string ReadString(int device, char field) {
98 string s = ReadField(device, field);
99 if (s != null && s[0] == '"' && s[s.Length - 1] == '"')
100 return s.Substring(1, s.Length - 2);
105 private int ReadInteger(int device, char field) {
106 string s = ReadField(device, field);
108 if (int.TryParse(s, out i))
114 private bool WriteField(int device, char field, string value) {
115 serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value);
116 for (int i = 0; i < 5; i++) {
117 string s = ReadLine(200);
118 Match match = Regex.Match(s, @"-\[0:" +
119 device.ToString(CultureInfo.InvariantCulture) + @"\]W" +
120 Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) +
128 private bool WriteInteger(int device, char field, int value) {
129 return WriteField(device, field,
130 value.ToString(CultureInfo.InvariantCulture));
133 private bool WriteString(int device, char field, string value) {
134 return WriteField(device, field, '"' + value + '"');
137 public Heatmaster(string portName, ISettings settings) {
139 this.portName = portName;
141 serialPort = new SerialPort(portName, 38400, Parity.None, 8,
144 serialPort.NewLine = ((char)0x0D).ToString();
146 hardwareRevision = ReadInteger(0, 'H');
147 firmwareRevision = ReadInteger(0, 'V');
148 firmwareCRC = ReadInteger(0, 'C');
150 int fanCount = Math.Min(ReadInteger(32, '?'), 4);
151 int temperatureCount = Math.Min(ReadInteger(48, '?'), 6);
152 int flowCount = Math.Min(ReadInteger(64, '?'), 1);
153 int relayCount = Math.Min(ReadInteger(80, '?'), 1);
155 fans = new Sensor[fanCount];
156 controls = new Sensor[fanCount];
157 for (int i = 0; i < fanCount; i++) {
159 string name = ReadString(device, 'C');
160 fans[i] = new Sensor(name, device, SensorType.Fan, this, settings);
161 fans[i].Value = ReadInteger(device, 'R');
162 ActivateSensor(fans[i]);
164 new Sensor(name, device, SensorType.Control, this, settings);
165 controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
166 ActivateSensor(controls[i]);
169 for (int i = 0; i < fanCount; i++) {
171 string name = ReadString(device, 'C');
173 fans[i].Value = ReadInteger(device, 'R');
174 ActivateSensor(fans[i]);
177 temperatures = new Sensor[temperatureCount];
178 for (int i = 0; i < temperatureCount; i++) {
180 string name = ReadString(device, 'C');
182 new Sensor(name, device, SensorType.Temperature, this, settings);
183 int value = ReadInteger(device, 'T');
184 temperatures[i].Value = 0.1f * value;
186 ActivateSensor(temperatures[i]);
189 flows = new Sensor[flowCount];
190 for (int i = 0; i < flowCount; i++) {
192 string name = ReadString(device, 'C');
193 flows[i] = new Sensor(name, device, SensorType.Flow, this, settings);
194 flows[i].Value = 0.1f * ReadInteger(device, 'L');
195 ActivateSensor(flows[i]);
198 relays = new Sensor[relayCount];
199 for (int i = 0; i < relayCount; i++) {
201 string name = ReadString(device, 'C');
203 new Sensor(name, device, SensorType.Control, this, settings);
204 relays[i].Value = 100 * ReadInteger(device, 'S');
205 ActivateSensor(relays[i]);
208 // set the update rate to 2 Hz
209 WriteInteger(0, 'L', 2);
213 } catch (IOException) { } catch (TimeoutException) { }
216 public override HardwareType HardwareType {
217 get { return HardwareType.Heatmaster; }
220 public override Identifier Identifier {
222 return new Identifier("heatmaster",
223 serialPort.PortName.TrimStart(new char[]{'/'}).ToLowerInvariant());
227 public override string Name {
228 get { return "Heatmaster"; }
231 private void ProcessUpdateLine(string line) {
232 Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)");
235 if (int.TryParse(match.Groups[1].Value, out device)) {
236 foreach (string s in match.Groups[2].Value.Split('|')) {
237 string[] strings = s.Split(':');
238 int[] ints = new int[strings.Length];
239 for (int i = 0; i < ints.Length; i++)
240 ints[i] = int.Parse(strings[i], CultureInfo.InvariantCulture);
243 if (ints.Length == 3 && ints[0] <= fans.Length) {
244 fans[ints[0] - 1].Value = ints[1];
245 controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2];
249 if (ints.Length == 2 && ints[0] <= temperatures.Length)
250 temperatures[ints[0] - 1].Value = 0.1f * ints[1];
253 if (ints.Length == 3 && ints[0] <= flows.Length)
254 flows[ints[0] - 1].Value = 0.1f * ints[1];
257 if (ints.Length == 2 && ints[0] <= relays.Length)
258 relays[ints[0] - 1].Value = 100 * ints[1];
266 public override void Update() {
270 while (serialPort.BytesToRead > 0) {
271 byte b = (byte)serialPort.ReadByte();
273 ProcessUpdateLine(buffer.ToString());
276 buffer.Append((char)b);
281 public override string GetReport() {
282 StringBuilder r = new StringBuilder();
284 r.AppendLine("Heatmaster");
287 r.AppendLine(portName);
288 r.Append("Hardware Revision: ");
289 r.AppendLine(hardwareRevision.ToString(CultureInfo.InvariantCulture));
290 r.Append("Firmware Revision: ");
291 r.AppendLine(firmwareRevision.ToString(CultureInfo.InvariantCulture));
292 r.Append("Firmware CRC: ");
293 r.AppendLine(firmwareCRC.ToString(CultureInfo.InvariantCulture));
299 public void Close() {
301 serialPort.Dispose();
305 public void Dispose() {
306 if (serialPort != null) {
307 serialPort.Dispose();