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) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Globalization;
14 using System.IO.Ports;
16 using System.Text.RegularExpressions;
17 using System.Threading;
19 namespace OpenHardwareMonitor.Hardware.Heatmaster {
20 internal class Heatmaster : Hardware, IDisposable {
22 private readonly string portName;
23 private SerialPort serialPort;
25 private readonly int hardwareRevision;
26 private readonly int firmwareRevision;
27 private readonly int firmwareCRC;
29 private readonly Sensor[] fans;
30 private readonly Sensor[] controls;
31 private readonly Sensor[] temperatures;
32 private readonly Sensor[] flows;
33 private readonly Sensor[] relays;
35 private readonly bool available;
37 private readonly StringBuilder buffer = new StringBuilder();
39 private string ReadLine(int timeout) {
41 StringBuilder builder = new StringBuilder();
42 while (i <= timeout) {
43 while (serialPort.BytesToRead > 0) {
44 byte b = (byte)serialPort.ReadByte();
46 case 0xAA: return ((char)b).ToString();
47 case 0x0D: return builder.ToString();
48 default: builder.Append((char)b); break;
54 throw new TimeoutException();
57 private string ReadField(int device, char field) {
58 serialPort.WriteLine("[0:" + device + "]R" + field);
59 for (int i = 0; i < 5; i++) {
60 string s = ReadLine(200);
61 Match match = Regex.Match(s, @"-\[0:" +
62 device.ToString(CultureInfo.InvariantCulture) + @"\]R" +
63 Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":(.*)");
65 return match.Groups[1].Value;
70 protected string ReadString(int device, char field) {
71 string s = ReadField(device, field);
72 if (s != null && s[0] == '"' && s[s.Length - 1] == '"')
73 return s.Substring(1, s.Length - 2);
78 protected int ReadInteger(int device, char field) {
79 string s = ReadField(device, field);
81 if (int.TryParse(s, out i))
87 private bool WriteField(int device, char field, string value) {
88 serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value);
89 for (int i = 0; i < 5; i++) {
90 string s = ReadLine(200);
91 Match match = Regex.Match(s, @"-\[0:" +
92 device.ToString(CultureInfo.InvariantCulture) + @"\]W" +
93 Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) +
101 protected bool WriteInteger(int device, char field, int value) {
102 return WriteField(device, field,
103 value.ToString(CultureInfo.InvariantCulture));
106 protected bool WriteString(int device, char field, string value) {
107 return WriteField(device, field, '"' + value + '"');
110 public Heatmaster(string portName, ISettings settings)
111 : base("Heatmaster", new Identifier("heatmaster",
112 portName.TrimStart(new [] {'/'}).ToLowerInvariant()), settings)
114 this.portName = portName;
116 serialPort = new SerialPort(portName, 38400, Parity.None, 8,
119 serialPort.NewLine = ((char)0x0D).ToString();
121 hardwareRevision = ReadInteger(0, 'H');
122 firmwareRevision = ReadInteger(0, 'V');
123 firmwareCRC = ReadInteger(0, 'C');
125 int fanCount = Math.Min(ReadInteger(32, '?'), 4);
126 int temperatureCount = Math.Min(ReadInteger(48, '?'), 6);
127 int flowCount = Math.Min(ReadInteger(64, '?'), 1);
128 int relayCount = Math.Min(ReadInteger(80, '?'), 1);
130 fans = new Sensor[fanCount];
131 controls = new Sensor[fanCount];
132 for (int i = 0; i < fanCount; i++) {
134 string name = ReadString(device, 'C');
135 fans[i] = new Sensor(name, device, SensorType.Fan, this, settings);
136 fans[i].Value = ReadInteger(device, 'R');
137 ActivateSensor(fans[i]);
139 new Sensor(name, device, SensorType.Control, this, settings);
140 controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
141 ActivateSensor(controls[i]);
144 temperatures = new Sensor[temperatureCount];
145 for (int i = 0; i < temperatureCount; i++) {
147 string name = ReadString(device, 'C');
149 new Sensor(name, device, SensorType.Temperature, this, settings);
150 int value = ReadInteger(device, 'T');
151 temperatures[i].Value = 0.1f * value;
153 ActivateSensor(temperatures[i]);
156 flows = new Sensor[flowCount];
157 for (int i = 0; i < flowCount; i++) {
159 string name = ReadString(device, 'C');
160 flows[i] = new Sensor(name, device, SensorType.Flow, this, settings);
161 flows[i].Value = 0.1f * ReadInteger(device, 'L');
162 ActivateSensor(flows[i]);
165 relays = new Sensor[relayCount];
166 for (int i = 0; i < relayCount; i++) {
168 string name = ReadString(device, 'C');
170 new Sensor(name, device, SensorType.Control, this, settings);
171 relays[i].Value = 100 * ReadInteger(device, 'S');
172 ActivateSensor(relays[i]);
175 // set the update rate to 2 Hz
176 WriteInteger(0, 'L', 2);
180 } catch (IOException) { } catch (TimeoutException) { }
183 public override HardwareType HardwareType {
184 get { return HardwareType.Heatmaster; }
187 private void ProcessUpdateLine(string line) {
188 Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)");
191 if (int.TryParse(match.Groups[1].Value, out device)) {
192 foreach (string s in match.Groups[2].Value.Split('|')) {
193 string[] strings = s.Split(':');
194 int[] ints = new int[strings.Length];
196 for (int i = 0; i < ints.Length; i++)
197 if (!int.TryParse(strings[i], out ints[i])) {
205 if (ints.Length == 3 && ints[0] <= fans.Length) {
206 fans[ints[0] - 1].Value = ints[1];
207 controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2];
211 if (ints.Length == 2 && ints[0] <= temperatures.Length)
212 temperatures[ints[0] - 1].Value = 0.1f * ints[1];
215 if (ints.Length == 3 && ints[0] <= flows.Length)
216 flows[ints[0] - 1].Value = 0.1f * ints[1];
219 if (ints.Length == 2 && ints[0] <= relays.Length)
220 relays[ints[0] - 1].Value = 100 * ints[1];
228 public override void Update() {
232 while (serialPort.IsOpen && serialPort.BytesToRead > 0) {
233 byte b = (byte)serialPort.ReadByte();
235 ProcessUpdateLine(buffer.ToString());
238 buffer.Append((char)b);
243 public override string GetReport() {
244 StringBuilder r = new StringBuilder();
246 r.AppendLine("Heatmaster");
249 r.AppendLine(portName);
250 r.Append("Hardware Revision: ");
251 r.AppendLine(hardwareRevision.ToString(CultureInfo.InvariantCulture));
252 r.Append("Firmware Revision: ");
253 r.AppendLine(firmwareRevision.ToString(CultureInfo.InvariantCulture));
254 r.Append("Firmware CRC: ");
255 r.AppendLine(firmwareCRC.ToString(CultureInfo.InvariantCulture));
261 public override void Close() {
263 serialPort.Dispose();
268 public void Dispose() {
269 if (serialPort != null) {
270 serialPort.Dispose();