Hardware/TBalancer/TBalancer.cs
author moel.mich
Tue, 14 Feb 2012 23:07:55 +0000
changeset 340 600962f8a298
parent 275 35788ddd1825
child 344 3145aadca3d2
permissions -rw-r--r--
Added a new sensor type "Factor" for dimensionless values (and similar) that are not to be shown as percent ("Level" type). Changed the write amplification sensor to use the new "Factor" sensor type. Added the temperature SMART attribute for Sandforce SSDs as hidden sensor (as it may show fake results on some hardware).
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@275
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Collections.Generic;
moel@166
    40
using System.Globalization;
moel@1
    41
using System.Text;
moel@1
    42
moel@1
    43
namespace OpenHardwareMonitor.Hardware.TBalancer {
moel@275
    44
  internal class TBalancer : Hardware {
moel@1
    45
moel@195
    46
    private readonly int portIndex;    
moel@195
    47
    private readonly byte protocolVersion;
moel@195
    48
    private readonly Sensor[] digitalTemperatures = new Sensor[8];
moel@195
    49
    private readonly Sensor[] analogTemperatures = new Sensor[4];
moel@195
    50
    private readonly Sensor[] sensorhubTemperatures = new Sensor[6];
moel@195
    51
    private readonly Sensor[] sensorhubFlows = new Sensor[2];
moel@195
    52
    private readonly Sensor[] fans = new Sensor[4];
moel@195
    53
    private readonly Sensor[] controls = new Sensor[4];
moel@195
    54
    private readonly Sensor[] miniNGTemperatures = new Sensor[4];
moel@195
    55
    private readonly Sensor[] miniNGFans = new Sensor[4];
moel@195
    56
    private readonly Sensor[] miniNGControls = new Sensor[4];
moel@195
    57
    private readonly List<ISensor> deactivating = new List<ISensor>();
moel@195
    58
moel@87
    59
    private FT_HANDLE handle;
moel@57
    60
    private int[] primaryData = new int[0];
moel@57
    61
    private int[] alternativeData = new int[0];
moel@1
    62
moel@1
    63
    public const byte STARTFLAG = 100;
moel@57
    64
    public const byte ENDFLAG = 254;
moel@57
    65
moel@57
    66
    private delegate void MethodDelegate();
moel@275
    67
    private readonly MethodDelegate alternativeRequest;
moel@1
    68
moel@275
    69
    public TBalancer(int portIndex, byte protocolVersion, ISettings settings)
moel@275
    70
      : base("T-Balancer bigNG",  new Identifier("bigng",
moel@275
    71
        portIndex.ToString(CultureInfo.InvariantCulture)), settings) 
moel@275
    72
    {
moel@165
    73
moel@87
    74
      this.portIndex = portIndex;
moel@33
    75
      this.protocolVersion = protocolVersion;
moel@1
    76
moel@195
    77
      ParameterDescription[] parameter = new [] {
moel@122
    78
        new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
moel@63
    79
      };
moel@57
    80
      int offset = 0;
moel@57
    81
      for (int i = 0; i < digitalTemperatures.Length; i++)
moel@88
    82
        digitalTemperatures[i] = new Sensor("Digital Sensor " + i,
moel@165
    83
          offset + i, SensorType.Temperature, this, parameter, settings);
moel@57
    84
      offset += digitalTemperatures.Length;
moel@57
    85
moel@57
    86
      for (int i = 0; i < analogTemperatures.Length; i++)
moel@88
    87
        analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1),
moel@165
    88
          offset + i, SensorType.Temperature, this, parameter, settings);
moel@57
    89
      offset += analogTemperatures.Length;
moel@57
    90
moel@57
    91
      for (int i = 0; i < sensorhubTemperatures.Length; i++)
moel@88
    92
        sensorhubTemperatures[i] = new Sensor("Sensorhub Sensor " + i,
moel@165
    93
          offset + i, SensorType.Temperature, this, parameter, settings);
moel@57
    94
      offset += sensorhubTemperatures.Length;
moel@57
    95
moel@57
    96
      for (int i = 0; i < miniNGTemperatures.Length; i++)
moel@63
    97
        miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) +
moel@165
    98
          " Sensor " + (i % 2 + 1), offset + i, SensorType.Temperature,
moel@165
    99
          this, parameter, settings);
moel@57
   100
      offset += miniNGTemperatures.Length;
moel@57
   101
moel@118
   102
      for (int i = 0; i < sensorhubFlows.Length; i++)
moel@118
   103
        sensorhubFlows[i] = new Sensor("Flowmeter " + (i + 1),
moel@195
   104
          i, SensorType.Flow, this, new [] {
moel@118
   105
            new ParameterDescription("Impulse Rate", 
moel@118
   106
              "The impulse rate of the flowmeter in pulses/L", 509)
moel@165
   107
          }, settings);
moel@118
   108
moel@118
   109
      for (int i = 0; i < controls.Length; i++) {
moel@137
   110
        controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, 
moel@165
   111
          this, settings);
moel@137
   112
      }
moel@137
   113
moel@137
   114
      for (int i = 0; i < miniNGControls.Length; i++) {
moel@137
   115
        miniNGControls[i] = new Sensor("miniNG #" + (i / 2 + 1) +
moel@165
   116
          " Fan Channel " + (i % 2 + 1), 4 + i, SensorType.Control, this, 
moel@165
   117
          settings);
moel@118
   118
      }
moel@118
   119
moel@57
   120
      alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
moel@57
   121
moel@87
   122
      Open();
moel@87
   123
      Update(); 
moel@1
   124
    }
moel@1
   125
moel@275
   126
    protected override void ActivateSensor(ISensor sensor) {
moel@1
   127
      deactivating.Remove(sensor);
moel@275
   128
      base.ActivateSensor(sensor);   
moel@275
   129
    } 
moel@1
   130
moel@275
   131
    protected override void DeactivateSensor(ISensor sensor) {
moel@1
   132
      if (deactivating.Contains(sensor)) {
moel@1
   133
        deactivating.Remove(sensor);
moel@275
   134
        base.DeactivateSensor(sensor);
moel@1
   135
      } else if (active.Contains(sensor)) {
moel@1
   136
        deactivating.Add(sensor);
moel@1
   137
      }     
moel@1
   138
    }
moel@1
   139
moel@57
   140
    private void ReadminiNG(int[] data, int number) {
moel@57
   141
      int offset = 1 + number * 65;
moel@57
   142
moel@57
   143
      if (data[offset + 61] != ENDFLAG)
moel@57
   144
        return;
moel@57
   145
moel@57
   146
      for (int i = 0; i < 2; i++) {
moel@57
   147
        Sensor sensor = miniNGTemperatures[number * 2 + i];
moel@57
   148
        if (data[offset + 7 + i] > 0) {
moel@63
   149
          sensor.Value = 0.5f * data[offset + 7 + i] + 
moel@63
   150
            sensor.Parameters[0].Value;
moel@57
   151
          ActivateSensor(sensor);
moel@57
   152
        } else {
moel@57
   153
          DeactivateSensor(sensor);
moel@57
   154
        }
moel@57
   155
      }
moel@57
   156
moel@57
   157
      for (int i = 0; i < 2; i++) {
moel@57
   158
        if (miniNGFans[number * 2 + i] == null)
moel@57
   159
          miniNGFans[number * 2 + i] = 
moel@88
   160
            new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1),
moel@165
   161
            4 + number * 2 + i, SensorType.Fan, this, settings);
moel@57
   162
        
moel@57
   163
        Sensor sensor = miniNGFans[number * 2 + i];
moel@57
   164
moel@57
   165
        sensor.Value = 20.0f * data[offset + 43 + 2 * i];
moel@57
   166
        ActivateSensor(sensor);
moel@57
   167
      }
moel@137
   168
moel@137
   169
      for (int i = 0; i < 2; i++) {
moel@137
   170
        Sensor sensor = miniNGControls[number * 2 + i];
moel@137
   171
        sensor.Value = data[offset + 15 + i];
moel@137
   172
        ActivateSensor(sensor);
moel@137
   173
      }
moel@57
   174
    }
moel@57
   175
moel@1
   176
    private void ReadData() {
moel@1
   177
      int[] data = new int[285];
moel@1
   178
      for (int i = 0; i < data.Length; i++)
moel@87
   179
        data[i] = FTD2XX.ReadByte(handle);
moel@137
   180
      
moel@57
   181
      if (data[0] != STARTFLAG) {
moel@87
   182
        FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX);   
moel@1
   183
        return;
moel@1
   184
      }
moel@1
   185
moel@73
   186
      if (data[1] == 255 || data[1] == 88) { // bigNG
moel@57
   187
moel@57
   188
        if (data[274] != protocolVersion) 
moel@57
   189
          return;
moel@57
   190
moel@57
   191
        this.primaryData = data;
moel@57
   192
moel@57
   193
        for (int i = 0; i < digitalTemperatures.Length; i++)
moel@57
   194
          if (data[238 + i] > 0) {
moel@63
   195
            digitalTemperatures[i].Value = 0.5f * data[238 + i] + 
moel@63
   196
              digitalTemperatures[i].Parameters[0].Value;
moel@57
   197
            ActivateSensor(digitalTemperatures[i]);
moel@57
   198
          } else {
moel@57
   199
            DeactivateSensor(digitalTemperatures[i]);
moel@57
   200
          }
moel@57
   201
moel@57
   202
        for (int i = 0; i < analogTemperatures.Length; i++)
moel@57
   203
          if (data[260 + i] > 0) {
moel@63
   204
            analogTemperatures[i].Value = 0.5f * data[260 + i] +
moel@63
   205
              analogTemperatures[i].Parameters[0].Value;
moel@57
   206
            ActivateSensor(analogTemperatures[i]);
moel@57
   207
          } else {
moel@57
   208
            DeactivateSensor(analogTemperatures[i]);
moel@57
   209
          }
moel@57
   210
moel@57
   211
        for (int i = 0; i < sensorhubTemperatures.Length; i++)
moel@57
   212
          if (data[246 + i] > 0) {
moel@63
   213
            sensorhubTemperatures[i].Value = 0.5f * data[246 + i] +
moel@63
   214
              sensorhubTemperatures[i].Parameters[0].Value;
moel@57
   215
            ActivateSensor(sensorhubTemperatures[i]);
moel@57
   216
          } else {
moel@57
   217
            DeactivateSensor(sensorhubTemperatures[i]);
moel@57
   218
          }
moel@57
   219
moel@57
   220
        for (int i = 0; i < sensorhubFlows.Length; i++)
moel@57
   221
          if (data[231 + i] > 0 && data[234] > 0) {
moel@66
   222
            float pulsesPerSecond = (data[231 + i] * 4.0f) / data[234];
moel@63
   223
            float pulsesPerLiter = sensorhubFlows[i].Parameters[0].Value;
moel@57
   224
            sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter;
moel@57
   225
            ActivateSensor(sensorhubFlows[i]);
moel@57
   226
          } else {
moel@57
   227
            DeactivateSensor(sensorhubFlows[i]);
moel@57
   228
          }
moel@86
   229
        
moel@57
   230
        for (int i = 0; i < fans.Length; i++) {
moel@57
   231
          float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]);
moel@57
   232
moel@57
   233
          if (fans[i] == null)
moel@134
   234
            fans[i] = new Sensor("Fan Channel " + i, i, SensorType.Fan,
moel@195
   235
              this, new [] { new ParameterDescription("MaxRPM", 
moel@63
   236
                  "Maximum revolutions per minute (RPM) of the fan.", maxRPM)
moel@165
   237
              }, settings);
moel@57
   238
moel@118
   239
          float value;
moel@118
   240
          if ((data[136] & (1 << i)) == 0)  // pwm mode
moel@118
   241
            value = 0.02f * data[137 + i];
moel@63
   242
          else // analog mode
moel@118
   243
            value = 0.01f * data[141 + i];
moel@118
   244
          
moel@118
   245
          fans[i].Value = fans[i].Parameters[0].Value * value;
moel@57
   246
          ActivateSensor(fans[i]);
moel@118
   247
moel@137
   248
          controls[i].Value = 100 * value;
moel@137
   249
          ActivateSensor(controls[i]);
moel@1
   250
        }
moel@1
   251
moel@57
   252
      } else if (data[1] == 253) { // miniNG #1
moel@57
   253
        this.alternativeData = data;
moel@1
   254
moel@57
   255
        ReadminiNG(data, 0);        
moel@57
   256
              
moel@137
   257
        if (data[66] == 253)  // miniNG #2
moel@57
   258
          ReadminiNG(data, 1);
moel@57
   259
      } 
moel@1
   260
    }
moel@1
   261
moel@275
   262
    public override HardwareType HardwareType {
moel@165
   263
      get { return HardwareType.TBalancer; }
moel@1
   264
    }
moel@1
   265
moel@275
   266
    public override string GetReport() {
moel@1
   267
      StringBuilder r = new StringBuilder();
moel@1
   268
moel@1
   269
      r.AppendLine("T-Balancer bigNG");
moel@1
   270
      r.AppendLine();
moel@166
   271
      r.Append("Port Index: "); 
moel@166
   272
      r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture));
moel@1
   273
      r.AppendLine();
moel@57
   274
moel@57
   275
      r.AppendLine("Primary System Information Answer");
moel@1
   276
      r.AppendLine();
moel@1
   277
      r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@1
   278
      r.AppendLine();
moel@1
   279
      for (int i = 0; i <= 0x11; i++) {
moel@166
   280
        r.Append(" "); 
moel@166
   281
        r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
moel@166
   282
        r.Append("  ");
moel@1
   283
        for (int j = 0; j <= 0xF; j++) {
moel@1
   284
          int index = ((i << 4) | j);
moel@57
   285
          if (index < primaryData.Length) {
moel@1
   286
            r.Append(" ");
moel@166
   287
            r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture));
moel@1
   288
          }          
moel@1
   289
        }
moel@1
   290
        r.AppendLine();
moel@1
   291
      }
moel@1
   292
      r.AppendLine();
moel@1
   293
moel@57
   294
      if (alternativeData.Length > 0) {
moel@57
   295
        r.AppendLine("Alternative System Information Answer");
moel@57
   296
        r.AppendLine();
moel@57
   297
        r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
moel@57
   298
        r.AppendLine();
moel@57
   299
        for (int i = 0; i <= 0x11; i++) {
moel@166
   300
          r.Append(" "); 
moel@166
   301
          r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
moel@166
   302
          r.Append("  ");
moel@57
   303
          for (int j = 0; j <= 0xF; j++) {
moel@57
   304
            int index = ((i << 4) | j);
moel@57
   305
            if (index < alternativeData.Length) {
moel@57
   306
              r.Append(" ");
moel@166
   307
              r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture));
moel@57
   308
            }
moel@57
   309
          }
moel@57
   310
          r.AppendLine();
moel@57
   311
        }
moel@57
   312
        r.AppendLine();
moel@57
   313
      }
moel@57
   314
moel@1
   315
      return r.ToString();
moel@1
   316
    }
moel@1
   317
moel@57
   318
    private void DelayedAlternativeRequest() {
moel@87
   319
      System.Threading.Thread.Sleep(500);      
moel@87
   320
      FTD2XX.Write(handle, new byte[] { 0x37 });
moel@57
   321
    }
moel@57
   322
moel@87
   323
    public void Open() {
moel@87
   324
      FTD2XX.FT_Open(portIndex, out handle); 
moel@87
   325
      FTD2XX.FT_SetBaudRate(handle, 19200);
moel@87
   326
      FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
moel@87
   327
      FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
moel@87
   328
        0x13);
moel@87
   329
      FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
moel@87
   330
      FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
moel@87
   331
    }
moel@57
   332
moel@275
   333
    public override void Update() {
moel@87
   334
      while (FTD2XX.BytesToRead(handle) >= 285)
moel@87
   335
        ReadData();
moel@87
   336
      if (FTD2XX.BytesToRead(handle) == 1)
moel@87
   337
        FTD2XX.ReadByte(handle);
moel@87
   338
moel@87
   339
      FTD2XX.Write(handle, new byte[] { 0x38 });
moel@87
   340
      alternativeRequest.BeginInvoke(null, null);
moel@1
   341
    }
moel@1
   342
moel@298
   343
    public override void Close() {
moel@87
   344
      FTD2XX.FT_Close(handle);
moel@298
   345
      base.Close();
moel@1
   346
    }
moel@1
   347
moel@1
   348
  }
moel@1
   349
}