1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/Hardware/Heatmaster/Heatmaster.cs Sun Aug 22 21:53:11 2010 +0000
1.3 @@ -0,0 +1,287 @@
1.4 +/*
1.5 +
1.6 + Version: MPL 1.1/GPL 2.0/LGPL 2.1
1.7 +
1.8 + The contents of this file are subject to the Mozilla Public License Version
1.9 + 1.1 (the "License"); you may not use this file except in compliance with
1.10 + the License. You may obtain a copy of the License at
1.11 +
1.12 + http://www.mozilla.org/MPL/
1.13 +
1.14 + Software distributed under the License is distributed on an "AS IS" basis,
1.15 + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1.16 + for the specific language governing rights and limitations under the License.
1.17 +
1.18 + The Original Code is the Open Hardware Monitor code.
1.19 +
1.20 + The Initial Developer of the Original Code is
1.21 + Michael Möller <m.moeller@gmx.ch>.
1.22 + Portions created by the Initial Developer are Copyright (C) 2010
1.23 + the Initial Developer. All Rights Reserved.
1.24 +
1.25 + Contributor(s):
1.26 +
1.27 + Alternatively, the contents of this file may be used under the terms of
1.28 + either the GNU General Public License Version 2 or later (the "GPL"), or
1.29 + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1.30 + in which case the provisions of the GPL or the LGPL are applicable instead
1.31 + of those above. If you wish to allow use of your version of this file only
1.32 + under the terms of either the GPL or the LGPL, and not to allow others to
1.33 + use your version of this file under the terms of the MPL, indicate your
1.34 + decision by deleting the provisions above and replace them with the notice
1.35 + and other provisions required by the GPL or the LGPL. If you do not delete
1.36 + the provisions above, a recipient may use your version of this file under
1.37 + the terms of any one of the MPL, the GPL or the LGPL.
1.38 +
1.39 +*/
1.40 +
1.41 +using System;
1.42 +using System.Collections.Generic;
1.43 +using System.IO;
1.44 +using System.IO.Ports;
1.45 +using System.Text;
1.46 +using System.Text.RegularExpressions;
1.47 +using System.Threading;
1.48 +
1.49 +namespace OpenHardwareMonitor.Hardware.Heatmaster {
1.50 + internal class Heatmaster : Hardware {
1.51 +
1.52 + private string portName;
1.53 + private SerialPort serialPort;
1.54 +
1.55 + private int hardwareRevision;
1.56 + private int firmwareRevision;
1.57 + private int firmwareCRC;
1.58 +
1.59 + private Sensor[] fans;
1.60 + private Sensor[] controls;
1.61 + private Sensor[] temperatures;
1.62 + private Sensor[] flows;
1.63 + private Sensor[] relays;
1.64 +
1.65 + private bool available = false;
1.66 +
1.67 + private string ReadLine(int timeout) {
1.68 + int i = 0;
1.69 + StringBuilder builder = new StringBuilder();
1.70 + while (i <= timeout) {
1.71 + while (serialPort.BytesToRead > 0) {
1.72 + byte b = (byte)serialPort.ReadByte();
1.73 + switch (b) {
1.74 + case 0xAA: return ((char)b).ToString();
1.75 + case 0x0D: return builder.ToString();
1.76 + default: builder.Append((char)b); break;
1.77 + }
1.78 + }
1.79 + i++;
1.80 + Thread.Sleep(1);
1.81 + }
1.82 + throw new TimeoutException();
1.83 + }
1.84 +
1.85 + private string ReadField(int device, char field) {
1.86 + serialPort.WriteLine("[0:" + device + "]R" + field);
1.87 + for (int i = 0; i < 5; i++) {
1.88 + string s = ReadLine(100);
1.89 + Match match = Regex.Match(s, @"-\[0:" + device.ToString() + @"\]R" +
1.90 + Regex.Escape(field.ToString()) + ":(.*)");
1.91 + if (match.Success)
1.92 + return match.Groups[1].Value;
1.93 + }
1.94 + return null;
1.95 + }
1.96 +
1.97 + private string ReadString(int device, char field) {
1.98 + string s = ReadField(device, field);
1.99 + if (s != null && s[0] == '"' && s[s.Length - 1] == '"')
1.100 + return s.Substring(1, s.Length - 2);
1.101 + else
1.102 + return null;
1.103 + }
1.104 +
1.105 + private int ReadInteger(int device, char field) {
1.106 + string s = ReadField(device, field);
1.107 + int i;
1.108 + if (int.TryParse(s, out i))
1.109 + return i;
1.110 + else
1.111 + return 0;
1.112 + }
1.113 +
1.114 + private bool WriteField(int device, char field, string value) {
1.115 + serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value);
1.116 + for (int i = 0; i < 5; i++) {
1.117 + string s = ReadLine(100);
1.118 + Match match = Regex.Match(s, @"-\[0:" + device.ToString() + @"\]W" +
1.119 + Regex.Escape(field.ToString()) + ":" + value);
1.120 + if (match.Success)
1.121 + return true;
1.122 + }
1.123 + return false;
1.124 + }
1.125 +
1.126 + private bool WriteInteger(int device, char field, int value) {
1.127 + return WriteField(device, field, value.ToString());
1.128 + }
1.129 +
1.130 + private bool WriteString(int device, char field, string value) {
1.131 + return WriteField(device, field, '"' + value + '"');
1.132 + }
1.133 +
1.134 + public Heatmaster(string portName, ISettings settings) {
1.135 +
1.136 + this.portName = portName;
1.137 + try {
1.138 + serialPort = new SerialPort(portName, 38400, Parity.None, 8,
1.139 + StopBits.One);
1.140 + serialPort.Open();
1.141 + serialPort.NewLine = ((char)0x0D).ToString();
1.142 +
1.143 + hardwareRevision = ReadInteger(0, 'H');
1.144 + firmwareRevision = ReadInteger(0, 'V');
1.145 + firmwareCRC = ReadInteger(0, 'C');
1.146 +
1.147 + int fanCount = ReadInteger(32, '?');
1.148 + int temperatureCount = ReadInteger(48, '?');
1.149 + int flowCount = ReadInteger(64, '?');
1.150 + int relayCount = ReadInteger(80, '?');
1.151 +
1.152 + fans = new Sensor[fanCount];
1.153 + controls = new Sensor[fanCount];
1.154 + for (int i = 0; i < fanCount; i++) {
1.155 + int device = 33 + i;
1.156 + string name = ReadString(device, 'C');
1.157 + fans[i] = new Sensor(name, device, SensorType.Fan, this, settings);
1.158 + fans[i].Value = ReadInteger(device, 'R');
1.159 + ActivateSensor(fans[i]);
1.160 + controls[i] =
1.161 + new Sensor(name, device, SensorType.Control, this, settings);
1.162 + controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
1.163 + ActivateSensor(controls[i]);
1.164 + }
1.165 +
1.166 + for (int i = 0; i < fanCount; i++) {
1.167 + int device = 33 + i;
1.168 + string name = ReadString(device, 'C');
1.169 +
1.170 + fans[i].Value = ReadInteger(device, 'R');
1.171 + ActivateSensor(fans[i]);
1.172 + }
1.173 +
1.174 + temperatures = new Sensor[temperatureCount];
1.175 + for (int i = 0; i < temperatureCount; i++) {
1.176 + int device = 49 + i;
1.177 + string name = ReadString(device, 'C');
1.178 + temperatures[i] =
1.179 + new Sensor(name, device, SensorType.Temperature, this, settings);
1.180 + int value = ReadInteger(device, 'T');
1.181 + temperatures[i].Value = 0.1f * value;
1.182 + if (value != -32768)
1.183 + ActivateSensor(temperatures[i]);
1.184 + }
1.185 +
1.186 + flows = new Sensor[flowCount];
1.187 + for (int i = 0; i < flowCount; i++) {
1.188 + int device = 65 + i;
1.189 + string name = ReadString(device, 'C');
1.190 + flows[i] = new Sensor(name, device, SensorType.Flow, this, settings);
1.191 + flows[i].Value = 0.1f * ReadInteger(device, 'L');
1.192 + ActivateSensor(flows[i]);
1.193 + }
1.194 +
1.195 + relays = new Sensor[relayCount];
1.196 + for (int i = 0; i < relayCount; i++) {
1.197 + int device = 81 + i;
1.198 + string name = ReadString(device, 'C');
1.199 + relays[i] =
1.200 + new Sensor(name, device, SensorType.Control, this, settings);
1.201 + relays[i].Value = 100 * ReadInteger(device, 'S');
1.202 + ActivateSensor(relays[i]);
1.203 + }
1.204 +
1.205 + // set the update rate to 2 Hz
1.206 + WriteInteger(0, 'L', 2);
1.207 +
1.208 + available = true;
1.209 +
1.210 + } catch (IOException) { } catch (TimeoutException) { }
1.211 + }
1.212 +
1.213 + public override HardwareType HardwareType {
1.214 + get { return HardwareType.Heatmaster; }
1.215 + }
1.216 +
1.217 + public override Identifier Identifier {
1.218 + get {
1.219 + return new Identifier("heatmaster",
1.220 + serialPort.PortName.TrimStart(new char[]{'/'}).ToLowerInvariant());
1.221 + }
1.222 + }
1.223 +
1.224 + public override string Name {
1.225 + get { return "Heatmaster"; }
1.226 + }
1.227 +
1.228 + public override void Update() {
1.229 + if (!available)
1.230 + return;
1.231 +
1.232 + while (serialPort.BytesToRead > 0) {
1.233 + Match match = Regex.Match(ReadLine(0), @">\[0:(\d+)\]([0-9:\|-]+)");
1.234 + if (match.Success) {
1.235 + int device;
1.236 + if (int.TryParse(match.Groups[1].Value, out device)) {
1.237 + foreach (string s in match.Groups[2].Value.Split('|')) {
1.238 + string[] strings = s.Split(':');
1.239 + int[] ints = new int[strings.Length];
1.240 + for (int i = 0; i < ints.Length; i++)
1.241 + ints[i] = int.Parse(strings[i]);
1.242 + switch (device) {
1.243 + case 32:
1.244 + if (ints.Length == 3 && ints[0] <= fans.Length) {
1.245 + fans[ints[0] - 1].Value = ints[1];
1.246 + controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2];
1.247 + }
1.248 + break;
1.249 + case 48:
1.250 + if (ints.Length == 2 && ints[0] <= temperatures.Length)
1.251 + temperatures[ints[0] - 1].Value = 0.1f * ints[1];
1.252 + break;
1.253 + case 64:
1.254 + if (ints.Length == 3 && ints[0] <= flows.Length)
1.255 + flows[ints[0] - 1].Value = 0.1f * ints[1];
1.256 + break;
1.257 + case 80:
1.258 + if (ints.Length == 2 && ints[0] <= relays.Length)
1.259 + relays[ints[0] - 1].Value = 100 * ints[1];
1.260 + break;
1.261 + }
1.262 + }
1.263 + }
1.264 + }
1.265 + }
1.266 + }
1.267 +
1.268 + public override string GetReport() {
1.269 + StringBuilder r = new StringBuilder();
1.270 +
1.271 + r.AppendLine("Heatmaster");
1.272 + r.AppendLine();
1.273 + r.Append("Port: ");
1.274 + r.AppendLine(portName);
1.275 + r.Append("Hardware Revision: ");
1.276 + r.AppendLine(hardwareRevision.ToString());
1.277 + r.Append("Firmware Revision: ");
1.278 + r.AppendLine(firmwareRevision.ToString());
1.279 + r.Append("Firmware CRC: ");
1.280 + r.AppendLine(firmwareCRC.ToString());
1.281 + r.AppendLine();
1.282 +
1.283 + return r.ToString();
1.284 + }
1.285 +
1.286 + public void Close() {
1.287 + serialPort.Close();
1.288 + }
1.289 + }
1.290 +}