Hardware/Heatmaster/Heatmaster.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 298 96263190189a
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
moel@171
     1
/*
moel@171
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@171
     6
 
moel@344
     7
  Copyright (C) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@171
     9
*/
moel@171
    10
moel@171
    11
using System;
moel@182
    12
using System.Globalization;
moel@171
    13
using System.IO;
moel@171
    14
using System.IO.Ports;
moel@171
    15
using System.Text;
moel@171
    16
using System.Text.RegularExpressions;
moel@171
    17
using System.Threading;
moel@171
    18
moel@171
    19
namespace OpenHardwareMonitor.Hardware.Heatmaster {
moel@182
    20
  internal class Heatmaster : Hardware, IDisposable {
moel@171
    21
moel@195
    22
    private readonly string portName;
moel@171
    23
    private SerialPort serialPort;
moel@171
    24
moel@195
    25
    private readonly int hardwareRevision;
moel@195
    26
    private readonly int firmwareRevision;
moel@195
    27
    private readonly int firmwareCRC;
moel@171
    28
moel@195
    29
    private readonly Sensor[] fans;
moel@195
    30
    private readonly Sensor[] controls;
moel@195
    31
    private readonly Sensor[] temperatures;
moel@195
    32
    private readonly Sensor[] flows;
moel@195
    33
    private readonly Sensor[] relays;
moel@171
    34
    
moel@195
    35
    private readonly bool available;
moel@171
    36
moel@195
    37
    private readonly StringBuilder buffer = new StringBuilder();
moel@172
    38
moel@171
    39
    private string ReadLine(int timeout) {
moel@171
    40
      int i = 0;
moel@171
    41
      StringBuilder builder = new StringBuilder();
moel@171
    42
      while (i <= timeout) {
moel@171
    43
        while (serialPort.BytesToRead > 0) {
moel@171
    44
          byte b = (byte)serialPort.ReadByte();
moel@171
    45
          switch (b) {
moel@171
    46
            case 0xAA: return ((char)b).ToString();
moel@171
    47
            case 0x0D: return builder.ToString();
moel@171
    48
            default: builder.Append((char)b); break;
moel@171
    49
          }
moel@171
    50
        }
moel@171
    51
        i++;
moel@171
    52
        Thread.Sleep(1);
moel@171
    53
      }
moel@171
    54
      throw new TimeoutException();
moel@171
    55
    }
moel@171
    56
moel@171
    57
    private string ReadField(int device, char field) {
moel@171
    58
      serialPort.WriteLine("[0:" + device + "]R" + field);
moel@171
    59
      for (int i = 0; i < 5; i++) {
moel@172
    60
        string s = ReadLine(200);
moel@182
    61
        Match match = Regex.Match(s, @"-\[0:" + 
moel@182
    62
          device.ToString(CultureInfo.InvariantCulture) + @"\]R" +
moel@182
    63
          Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":(.*)");
moel@171
    64
        if (match.Success) 
moel@171
    65
          return match.Groups[1].Value;
moel@171
    66
      }
moel@171
    67
      return null;
moel@171
    68
    }
moel@171
    69
moel@195
    70
    protected string ReadString(int device, char field) {
moel@171
    71
      string s = ReadField(device, field);
moel@171
    72
      if (s != null && s[0] == '"' && s[s.Length - 1] == '"')
moel@171
    73
        return s.Substring(1, s.Length - 2);
moel@171
    74
      else
moel@171
    75
        return null;
moel@171
    76
    }
moel@171
    77
moel@195
    78
    protected int ReadInteger(int device, char field) {
moel@171
    79
      string s = ReadField(device, field);      
moel@171
    80
      int i;
moel@171
    81
      if (int.TryParse(s, out i))
moel@171
    82
        return i;
moel@171
    83
      else
moel@171
    84
        return 0;
moel@171
    85
    }
moel@171
    86
moel@171
    87
    private bool WriteField(int device, char field, string value) {
moel@171
    88
      serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value);
moel@171
    89
      for (int i = 0; i < 5; i++) {
moel@172
    90
        string s = ReadLine(200);
moel@182
    91
        Match match = Regex.Match(s, @"-\[0:" + 
moel@182
    92
          device.ToString(CultureInfo.InvariantCulture) + @"\]W" + 
moel@182
    93
          Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) +
moel@182
    94
          ":" + value);
moel@171
    95
        if (match.Success)
moel@171
    96
          return true;
moel@171
    97
      }
moel@171
    98
      return false;
moel@171
    99
    }
moel@171
   100
moel@195
   101
    protected bool WriteInteger(int device, char field, int value) {
moel@182
   102
      return WriteField(device, field, 
moel@182
   103
        value.ToString(CultureInfo.InvariantCulture));
moel@171
   104
    }
moel@171
   105
moel@195
   106
    protected bool WriteString(int device, char field, string value) {
moel@171
   107
      return WriteField(device, field, '"' + value + '"');
moel@171
   108
    }
moel@171
   109
moel@275
   110
    public Heatmaster(string portName, ISettings settings) 
moel@275
   111
      : base("Heatmaster", new Identifier("heatmaster",
moel@275
   112
        portName.TrimStart(new [] {'/'}).ToLowerInvariant()), settings)
moel@275
   113
    {
moel@171
   114
      this.portName = portName;
moel@171
   115
      try {
moel@171
   116
        serialPort = new SerialPort(portName, 38400, Parity.None, 8,
moel@171
   117
          StopBits.One);
moel@171
   118
        serialPort.Open();
moel@171
   119
        serialPort.NewLine = ((char)0x0D).ToString();
moel@171
   120
        
moel@171
   121
        hardwareRevision = ReadInteger(0, 'H');
moel@171
   122
        firmwareRevision = ReadInteger(0, 'V');
moel@171
   123
        firmwareCRC = ReadInteger(0, 'C');
moel@171
   124
moel@173
   125
        int fanCount = Math.Min(ReadInteger(32, '?'), 4);
moel@173
   126
        int temperatureCount = Math.Min(ReadInteger(48, '?'), 6);
moel@173
   127
        int flowCount = Math.Min(ReadInteger(64, '?'), 1);
moel@173
   128
        int relayCount =  Math.Min(ReadInteger(80, '?'), 1);
moel@171
   129
moel@171
   130
        fans = new Sensor[fanCount];
moel@171
   131
        controls = new Sensor[fanCount];
moel@171
   132
        for (int i = 0; i < fanCount; i++) {
moel@171
   133
          int device = 33 + i;
moel@171
   134
          string name = ReadString(device, 'C');
moel@171
   135
          fans[i] = new Sensor(name, device, SensorType.Fan, this, settings);          
moel@171
   136
          fans[i].Value = ReadInteger(device, 'R');
moel@171
   137
          ActivateSensor(fans[i]);
moel@171
   138
          controls[i] =
moel@171
   139
            new Sensor(name, device, SensorType.Control, this, settings);
moel@171
   140
          controls[i].Value = (100 / 255.0f) * ReadInteger(device, 'P');
moel@171
   141
          ActivateSensor(controls[i]);
moel@195
   142
        }       
moel@171
   143
moel@171
   144
        temperatures = new Sensor[temperatureCount];
moel@171
   145
        for (int i = 0; i < temperatureCount; i++) {
moel@171
   146
          int device = 49 + i;
moel@171
   147
          string name = ReadString(device, 'C');
moel@171
   148
          temperatures[i] =
moel@171
   149
            new Sensor(name, device, SensorType.Temperature, this, settings);
moel@171
   150
          int value = ReadInteger(device, 'T');
moel@171
   151
          temperatures[i].Value = 0.1f * value;
moel@171
   152
          if (value != -32768)
moel@171
   153
            ActivateSensor(temperatures[i]);
moel@171
   154
        }
moel@171
   155
moel@171
   156
        flows = new Sensor[flowCount];
moel@171
   157
        for (int i = 0; i < flowCount; i++) {
moel@171
   158
          int device = 65 + i;
moel@171
   159
          string name = ReadString(device, 'C');
moel@171
   160
          flows[i] = new Sensor(name, device, SensorType.Flow, this, settings);
moel@171
   161
          flows[i].Value = 0.1f * ReadInteger(device, 'L');
moel@171
   162
          ActivateSensor(flows[i]);
moel@171
   163
        }
moel@171
   164
moel@171
   165
        relays = new Sensor[relayCount];
moel@171
   166
        for (int i = 0; i < relayCount; i++) {
moel@171
   167
          int device = 81 + i;
moel@171
   168
          string name = ReadString(device, 'C');
moel@171
   169
          relays[i] = 
moel@171
   170
            new Sensor(name, device, SensorType.Control, this, settings);
moel@171
   171
          relays[i].Value = 100 * ReadInteger(device, 'S');
moel@171
   172
          ActivateSensor(relays[i]);
moel@171
   173
        }
moel@171
   174
moel@171
   175
        // set the update rate to 2 Hz
moel@171
   176
        WriteInteger(0, 'L', 2);
moel@171
   177
        
moel@171
   178
        available = true;
moel@171
   179
moel@171
   180
      } catch (IOException) { } catch (TimeoutException) { }      
moel@171
   181
    }
moel@171
   182
moel@171
   183
    public override HardwareType HardwareType {
moel@171
   184
      get { return HardwareType.Heatmaster; }
moel@171
   185
    }
moel@171
   186
moel@172
   187
    private void ProcessUpdateLine(string line) {
moel@172
   188
      Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)");
moel@172
   189
      if (match.Success) {
moel@172
   190
        int device;
moel@172
   191
        if (int.TryParse(match.Groups[1].Value, out device)) {
moel@172
   192
          foreach (string s in match.Groups[2].Value.Split('|')) {
moel@172
   193
            string[] strings = s.Split(':');
moel@260
   194
            int[] ints = new int[strings.Length];            
moel@260
   195
            bool valid = true;
moel@172
   196
            for (int i = 0; i < ints.Length; i++)
moel@260
   197
              if (!int.TryParse(strings[i], out ints[i])) {
moel@260
   198
                valid = false;
moel@260
   199
                break;
moel@260
   200
              }
moel@260
   201
            if (!valid)
moel@260
   202
              continue; 
moel@172
   203
            switch (device) {
moel@172
   204
              case 32:
moel@172
   205
                if (ints.Length == 3 && ints[0] <= fans.Length) {
moel@172
   206
                  fans[ints[0] - 1].Value = ints[1];
moel@172
   207
                  controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2];
moel@172
   208
                }
moel@172
   209
                break;
moel@172
   210
              case 48:
moel@172
   211
                if (ints.Length == 2 && ints[0] <= temperatures.Length)
moel@172
   212
                  temperatures[ints[0] - 1].Value = 0.1f * ints[1];
moel@172
   213
                break;
moel@172
   214
              case 64:
moel@172
   215
                if (ints.Length == 3 && ints[0] <= flows.Length)
moel@172
   216
                  flows[ints[0] - 1].Value = 0.1f * ints[1];
moel@172
   217
                break;
moel@172
   218
              case 80:
moel@172
   219
                if (ints.Length == 2 && ints[0] <= relays.Length)
moel@172
   220
                  relays[ints[0] - 1].Value = 100 * ints[1];
moel@172
   221
                break;
moel@172
   222
            }
moel@172
   223
          }
moel@172
   224
        }
moel@172
   225
      }
moel@172
   226
    }
moel@172
   227
moel@171
   228
    public override void Update() {
moel@171
   229
      if (!available)
moel@171
   230
        return;
moel@171
   231
moel@261
   232
      while (serialPort.IsOpen &&  serialPort.BytesToRead > 0) {
moel@172
   233
        byte b = (byte)serialPort.ReadByte();
moel@172
   234
        if (b == 0x0D) {
moel@172
   235
          ProcessUpdateLine(buffer.ToString());
moel@172
   236
          buffer.Length = 0;
moel@172
   237
        } else {
moel@172
   238
          buffer.Append((char)b);
moel@171
   239
        }
moel@171
   240
      }
moel@171
   241
    }
moel@171
   242
moel@171
   243
    public override string GetReport() {
moel@171
   244
      StringBuilder r = new StringBuilder();
moel@171
   245
moel@171
   246
      r.AppendLine("Heatmaster");
moel@171
   247
      r.AppendLine();
moel@171
   248
      r.Append("Port: ");
moel@171
   249
      r.AppendLine(portName);
moel@171
   250
      r.Append("Hardware Revision: ");
moel@182
   251
      r.AppendLine(hardwareRevision.ToString(CultureInfo.InvariantCulture));
moel@171
   252
      r.Append("Firmware Revision: ");
moel@182
   253
      r.AppendLine(firmwareRevision.ToString(CultureInfo.InvariantCulture));
moel@171
   254
      r.Append("Firmware CRC: ");
moel@182
   255
      r.AppendLine(firmwareCRC.ToString(CultureInfo.InvariantCulture));
moel@171
   256
      r.AppendLine();
moel@171
   257
moel@171
   258
      return r.ToString();
moel@171
   259
    }
moel@171
   260
moel@298
   261
    public override void Close() {
moel@171
   262
      serialPort.Close();
moel@182
   263
      serialPort.Dispose();
moel@182
   264
      serialPort = null;
moel@298
   265
      base.Close();
moel@182
   266
    }
moel@182
   267
moel@182
   268
    public void Dispose() {
moel@182
   269
      if (serialPort != null) {
moel@182
   270
        serialPort.Dispose();
moel@182
   271
        serialPort = null;
moel@182
   272
      }
moel@171
   273
    }
moel@171
   274
  }
moel@171
   275
}