Fixed Issue 105 and Issue 106.
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.Collections.Generic;
41 using System.IO.Ports;
43 using System.Text.RegularExpressions;
44 using System.Threading;
46 namespace OpenHardwareMonitor.Hardware.Heatmaster {
47 internal class Heatmaster : Hardware {
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:" + device.ToString() + @"\]R" +
89 Regex.Escape(field.ToString()) + ":(.*)");
91 return match.Groups[1].Value;
96 private string ReadString(int device, char field) {
97 string s = ReadField(device, field);
98 if (s != null && s[0] == '"' && s[s.Length - 1] == '"')
99 return s.Substring(1, s.Length - 2);
104 private int ReadInteger(int device, char field) {
105 string s = ReadField(device, field);
107 if (int.TryParse(s, out i))
113 private bool WriteField(int device, char field, string value) {
114 serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value);
115 for (int i = 0; i < 5; i++) {
116 string s = ReadLine(200);
117 Match match = Regex.Match(s, @"-\[0:" + device.ToString() + @"\]W" +
118 Regex.Escape(field.ToString()) + ":" + value);
125 private bool WriteInteger(int device, char field, int value) {
126 return WriteField(device, field, value.ToString());
129 private bool WriteString(int device, char field, string value) {
130 return WriteField(device, field, '"' + value + '"');
133 public Heatmaster(string portName, ISettings settings) {
135 this.portName = portName;
137 serialPort = new SerialPort(portName, 38400, Parity.None, 8,
140 serialPort.NewLine = ((char)0x0D).ToString();
142 hardwareRevision = ReadInteger(0, 'H');
143 firmwareRevision = ReadInteger(0, 'V');
144 firmwareCRC = ReadInteger(0, 'C');
146 int fanCount = Math.Min(ReadInteger(32, '?'), 4);
147 int temperatureCount = Math.Min(ReadInteger(48, '?'), 6);
148 int flowCount = Math.Min(ReadInteger(64, '?'), 1);
149 int relayCount = Math.Min(ReadInteger(80, '?'), 1);
151 fans = new Sensor[fanCount];
152 controls = new Sensor[fanCount];
153 for (int i = 0; i < fanCount; i++) {
155 string name = ReadString(device, 'C');
156 fans[i] = new Sensor(name, device, SensorType.Fan, this, settings);
157 fans[i].Value = ReadInteger(device, 'R');
158 ActivateSensor(fans[i]);
160 new Sensor(name, device, SensorType.Control, this, settings);
161 controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
162 ActivateSensor(controls[i]);
165 for (int i = 0; i < fanCount; i++) {
167 string name = ReadString(device, 'C');
169 fans[i].Value = ReadInteger(device, 'R');
170 ActivateSensor(fans[i]);
173 temperatures = new Sensor[temperatureCount];
174 for (int i = 0; i < temperatureCount; i++) {
176 string name = ReadString(device, 'C');
178 new Sensor(name, device, SensorType.Temperature, this, settings);
179 int value = ReadInteger(device, 'T');
180 temperatures[i].Value = 0.1f * value;
182 ActivateSensor(temperatures[i]);
185 flows = new Sensor[flowCount];
186 for (int i = 0; i < flowCount; i++) {
188 string name = ReadString(device, 'C');
189 flows[i] = new Sensor(name, device, SensorType.Flow, this, settings);
190 flows[i].Value = 0.1f * ReadInteger(device, 'L');
191 ActivateSensor(flows[i]);
194 relays = new Sensor[relayCount];
195 for (int i = 0; i < relayCount; i++) {
197 string name = ReadString(device, 'C');
199 new Sensor(name, device, SensorType.Control, this, settings);
200 relays[i].Value = 100 * ReadInteger(device, 'S');
201 ActivateSensor(relays[i]);
204 // set the update rate to 2 Hz
205 WriteInteger(0, 'L', 2);
209 } catch (IOException) { } catch (TimeoutException) { }
212 public override HardwareType HardwareType {
213 get { return HardwareType.Heatmaster; }
216 public override Identifier Identifier {
218 return new Identifier("heatmaster",
219 serialPort.PortName.TrimStart(new char[]{'/'}).ToLowerInvariant());
223 public override string Name {
224 get { return "Heatmaster"; }
227 private void ProcessUpdateLine(string line) {
228 Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)");
231 if (int.TryParse(match.Groups[1].Value, out device)) {
232 foreach (string s in match.Groups[2].Value.Split('|')) {
233 string[] strings = s.Split(':');
234 int[] ints = new int[strings.Length];
235 for (int i = 0; i < ints.Length; i++)
236 ints[i] = int.Parse(strings[i]);
239 if (ints.Length == 3 && ints[0] <= fans.Length) {
240 fans[ints[0] - 1].Value = ints[1];
241 controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2];
245 if (ints.Length == 2 && ints[0] <= temperatures.Length)
246 temperatures[ints[0] - 1].Value = 0.1f * ints[1];
249 if (ints.Length == 3 && ints[0] <= flows.Length)
250 flows[ints[0] - 1].Value = 0.1f * ints[1];
253 if (ints.Length == 2 && ints[0] <= relays.Length)
254 relays[ints[0] - 1].Value = 100 * ints[1];
262 public override void Update() {
266 while (serialPort.BytesToRead > 0) {
267 byte b = (byte)serialPort.ReadByte();
269 ProcessUpdateLine(buffer.ToString());
272 buffer.Append((char)b);
277 public override string GetReport() {
278 StringBuilder r = new StringBuilder();
280 r.AppendLine("Heatmaster");
283 r.AppendLine(portName);
284 r.Append("Hardware Revision: ");
285 r.AppendLine(hardwareRevision.ToString());
286 r.Append("Firmware Revision: ");
287 r.AppendLine(firmwareRevision.ToString());
288 r.Append("Firmware CRC: ");
289 r.AppendLine(firmwareCRC.ToString());
295 public void Close() {