Hardware/Heatmaster/Heatmaster.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 298 96263190189a
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
     1 /*
     2  
     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/.
     6  
     7   Copyright (C) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Globalization;
    13 using System.IO;
    14 using System.IO.Ports;
    15 using System.Text;
    16 using System.Text.RegularExpressions;
    17 using System.Threading;
    18 
    19 namespace OpenHardwareMonitor.Hardware.Heatmaster {
    20   internal class Heatmaster : Hardware, IDisposable {
    21 
    22     private readonly string portName;
    23     private SerialPort serialPort;
    24 
    25     private readonly int hardwareRevision;
    26     private readonly int firmwareRevision;
    27     private readonly int firmwareCRC;
    28 
    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;
    34     
    35     private readonly bool available;
    36 
    37     private readonly StringBuilder buffer = new StringBuilder();
    38 
    39     private string ReadLine(int timeout) {
    40       int i = 0;
    41       StringBuilder builder = new StringBuilder();
    42       while (i <= timeout) {
    43         while (serialPort.BytesToRead > 0) {
    44           byte b = (byte)serialPort.ReadByte();
    45           switch (b) {
    46             case 0xAA: return ((char)b).ToString();
    47             case 0x0D: return builder.ToString();
    48             default: builder.Append((char)b); break;
    49           }
    50         }
    51         i++;
    52         Thread.Sleep(1);
    53       }
    54       throw new TimeoutException();
    55     }
    56 
    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)) + ":(.*)");
    64         if (match.Success) 
    65           return match.Groups[1].Value;
    66       }
    67       return null;
    68     }
    69 
    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);
    74       else
    75         return null;
    76     }
    77 
    78     protected int ReadInteger(int device, char field) {
    79       string s = ReadField(device, field);      
    80       int i;
    81       if (int.TryParse(s, out i))
    82         return i;
    83       else
    84         return 0;
    85     }
    86 
    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)) +
    94           ":" + value);
    95         if (match.Success)
    96           return true;
    97       }
    98       return false;
    99     }
   100 
   101     protected bool WriteInteger(int device, char field, int value) {
   102       return WriteField(device, field, 
   103         value.ToString(CultureInfo.InvariantCulture));
   104     }
   105 
   106     protected bool WriteString(int device, char field, string value) {
   107       return WriteField(device, field, '"' + value + '"');
   108     }
   109 
   110     public Heatmaster(string portName, ISettings settings) 
   111       : base("Heatmaster", new Identifier("heatmaster",
   112         portName.TrimStart(new [] {'/'}).ToLowerInvariant()), settings)
   113     {
   114       this.portName = portName;
   115       try {
   116         serialPort = new SerialPort(portName, 38400, Parity.None, 8,
   117           StopBits.One);
   118         serialPort.Open();
   119         serialPort.NewLine = ((char)0x0D).ToString();
   120         
   121         hardwareRevision = ReadInteger(0, 'H');
   122         firmwareRevision = ReadInteger(0, 'V');
   123         firmwareCRC = ReadInteger(0, 'C');
   124 
   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);
   129 
   130         fans = new Sensor[fanCount];
   131         controls = new Sensor[fanCount];
   132         for (int i = 0; i < fanCount; i++) {
   133           int device = 33 + 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]);
   138           controls[i] =
   139             new Sensor(name, device, SensorType.Control, this, settings);
   140           controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
   141           ActivateSensor(controls[i]);
   142         }       
   143 
   144         temperatures = new Sensor[temperatureCount];
   145         for (int i = 0; i < temperatureCount; i++) {
   146           int device = 49 + i;
   147           string name = ReadString(device, 'C');
   148           temperatures[i] =
   149             new Sensor(name, device, SensorType.Temperature, this, settings);
   150           int value = ReadInteger(device, 'T');
   151           temperatures[i].Value = 0.1f * value;
   152           if (value != -32768)
   153             ActivateSensor(temperatures[i]);
   154         }
   155 
   156         flows = new Sensor[flowCount];
   157         for (int i = 0; i < flowCount; i++) {
   158           int device = 65 + 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]);
   163         }
   164 
   165         relays = new Sensor[relayCount];
   166         for (int i = 0; i < relayCount; i++) {
   167           int device = 81 + i;
   168           string name = ReadString(device, 'C');
   169           relays[i] = 
   170             new Sensor(name, device, SensorType.Control, this, settings);
   171           relays[i].Value = 100 * ReadInteger(device, 'S');
   172           ActivateSensor(relays[i]);
   173         }
   174 
   175         // set the update rate to 2 Hz
   176         WriteInteger(0, 'L', 2);
   177         
   178         available = true;
   179 
   180       } catch (IOException) { } catch (TimeoutException) { }      
   181     }
   182 
   183     public override HardwareType HardwareType {
   184       get { return HardwareType.Heatmaster; }
   185     }
   186 
   187     private void ProcessUpdateLine(string line) {
   188       Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)");
   189       if (match.Success) {
   190         int device;
   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];            
   195             bool valid = true;
   196             for (int i = 0; i < ints.Length; i++)
   197               if (!int.TryParse(strings[i], out ints[i])) {
   198                 valid = false;
   199                 break;
   200               }
   201             if (!valid)
   202               continue; 
   203             switch (device) {
   204               case 32:
   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];
   208                 }
   209                 break;
   210               case 48:
   211                 if (ints.Length == 2 && ints[0] <= temperatures.Length)
   212                   temperatures[ints[0] - 1].Value = 0.1f * ints[1];
   213                 break;
   214               case 64:
   215                 if (ints.Length == 3 && ints[0] <= flows.Length)
   216                   flows[ints[0] - 1].Value = 0.1f * ints[1];
   217                 break;
   218               case 80:
   219                 if (ints.Length == 2 && ints[0] <= relays.Length)
   220                   relays[ints[0] - 1].Value = 100 * ints[1];
   221                 break;
   222             }
   223           }
   224         }
   225       }
   226     }
   227 
   228     public override void Update() {
   229       if (!available)
   230         return;
   231 
   232       while (serialPort.IsOpen &&  serialPort.BytesToRead > 0) {
   233         byte b = (byte)serialPort.ReadByte();
   234         if (b == 0x0D) {
   235           ProcessUpdateLine(buffer.ToString());
   236           buffer.Length = 0;
   237         } else {
   238           buffer.Append((char)b);
   239         }
   240       }
   241     }
   242 
   243     public override string GetReport() {
   244       StringBuilder r = new StringBuilder();
   245 
   246       r.AppendLine("Heatmaster");
   247       r.AppendLine();
   248       r.Append("Port: ");
   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));
   256       r.AppendLine();
   257 
   258       return r.ToString();
   259     }
   260 
   261     public override void Close() {
   262       serialPort.Close();
   263       serialPort.Dispose();
   264       serialPort = null;
   265       base.Close();
   266     }
   267 
   268     public void Dispose() {
   269       if (serialPort != null) {
   270         serialPort.Dispose();
   271         serialPort = null;
   272       }
   273     }
   274   }
   275 }