Hardware/TBalancer/TBalancer.cs
author moel.mich
Mon, 07 Jun 2010 20:35:05 +0000
changeset 137 9ed52fa44ecf
parent 134 8b3b9b2e28e5
child 165 813d8bc3192f
permissions -rw-r--r--
Added support for a second miniNG on the T-Balancer bigNG.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     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
     8  
     9   http://www.mozilla.org/MPL/
    10 
    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.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    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) 2009-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    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.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.Configuration;
    41 using System.Drawing;
    42 using System.Text;
    43 
    44 namespace OpenHardwareMonitor.Hardware.TBalancer {
    45   public class TBalancer : IHardware {
    46 
    47     private int portIndex;
    48     private FT_HANDLE handle;
    49     private Image icon;
    50     private byte protocolVersion;
    51     private Sensor[] digitalTemperatures = new Sensor[8];
    52     private Sensor[] analogTemperatures = new Sensor[4];
    53     private Sensor[] sensorhubTemperatures = new Sensor[6];
    54     private Sensor[] sensorhubFlows = new Sensor[2];
    55     private Sensor[] fans = new Sensor[4];
    56     private Sensor[] controls = new Sensor[4];
    57     private Sensor[] miniNGTemperatures = new Sensor[4];
    58     private Sensor[] miniNGFans = new Sensor[4];
    59     private Sensor[] miniNGControls = new Sensor[4];
    60     private List<ISensor> active = new List<ISensor>();
    61     private List<ISensor> deactivating = new List<ISensor>();
    62     private int[] primaryData = new int[0];
    63     private int[] alternativeData = new int[0];
    64 
    65     public const byte STARTFLAG = 100;
    66     public const byte ENDFLAG = 254;
    67 
    68     private delegate void MethodDelegate();
    69     private MethodDelegate alternativeRequest;    
    70 
    71     public TBalancer(int portIndex, byte protocolVersion) {
    72       this.portIndex = portIndex;
    73       this.icon = Utilities.EmbeddedResources.GetImage("bigng.png");
    74       this.protocolVersion = protocolVersion;
    75 
    76       ParameterDescription[] parameter = new ParameterDescription[] {
    77         new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
    78       };
    79       int offset = 0;
    80       for (int i = 0; i < digitalTemperatures.Length; i++)
    81         digitalTemperatures[i] = new Sensor("Digital Sensor " + i,
    82           offset + i, SensorType.Temperature, this, parameter);
    83       offset += digitalTemperatures.Length;
    84 
    85       for (int i = 0; i < analogTemperatures.Length; i++)
    86         analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1),
    87           offset + i, SensorType.Temperature, this, parameter);
    88       offset += analogTemperatures.Length;
    89 
    90       for (int i = 0; i < sensorhubTemperatures.Length; i++)
    91         sensorhubTemperatures[i] = new Sensor("Sensorhub Sensor " + i,
    92           offset + i, SensorType.Temperature, this, parameter);
    93       offset += sensorhubTemperatures.Length;
    94 
    95       for (int i = 0; i < miniNGTemperatures.Length; i++)
    96         miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) +
    97           " Sensor " + (i % 2 + 1), offset + i, SensorType.Temperature, 
    98           this, parameter);
    99       offset += miniNGTemperatures.Length;
   100 
   101       for (int i = 0; i < sensorhubFlows.Length; i++)
   102         sensorhubFlows[i] = new Sensor("Flowmeter " + (i + 1),
   103           i, SensorType.Flow, this, new ParameterDescription[] {
   104             new ParameterDescription("Impulse Rate", 
   105               "The impulse rate of the flowmeter in pulses/L", 509)
   106           });
   107 
   108       for (int i = 0; i < controls.Length; i++) {
   109         controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, 
   110           this, null);
   111       }
   112 
   113       for (int i = 0; i < miniNGControls.Length; i++) {
   114         miniNGControls[i] = new Sensor("miniNG #" + (i / 2 + 1) +
   115           " Fan Channel " + (i % 2 + 1), 4 + i, SensorType.Control, this, null);
   116       }
   117 
   118       alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
   119 
   120       Open();
   121       Update(); 
   122     }
   123 
   124     private void ActivateSensor(Sensor sensor) {
   125       deactivating.Remove(sensor);
   126       if (!active.Contains(sensor)) {
   127         active.Add(sensor);
   128         if (SensorAdded != null)
   129           SensorAdded(sensor);
   130       }      
   131     }
   132 
   133     private void DeactivateSensor(Sensor sensor) {
   134       if (deactivating.Contains(sensor)) {
   135         active.Remove(sensor);
   136         deactivating.Remove(sensor);
   137         if (SensorRemoved != null)
   138           SensorRemoved(sensor);
   139       } else if (active.Contains(sensor)) {
   140         deactivating.Add(sensor);
   141       }     
   142     }
   143 
   144     private void ReadminiNG(int[] data, int number) {
   145       int offset = 1 + number * 65;
   146 
   147       if (data[offset + 61] != ENDFLAG)
   148         return;
   149 
   150       for (int i = 0; i < 2; i++) {
   151         Sensor sensor = miniNGTemperatures[number * 2 + i];
   152         if (data[offset + 7 + i] > 0) {
   153           sensor.Value = 0.5f * data[offset + 7 + i] + 
   154             sensor.Parameters[0].Value;
   155           ActivateSensor(sensor);
   156         } else {
   157           DeactivateSensor(sensor);
   158         }
   159       }
   160 
   161       for (int i = 0; i < 2; i++) {
   162         float maxRPM = 20.0f * data[offset + 44 + 2 * i];
   163 
   164         if (miniNGFans[number * 2 + i] == null)
   165           miniNGFans[number * 2 + i] = 
   166             new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1),
   167             4 + number * 2 + i, SensorType.Fan, this, null);
   168         
   169         Sensor sensor = miniNGFans[number * 2 + i];
   170 
   171         sensor.Value = 20.0f * data[offset + 43 + 2 * i];
   172         ActivateSensor(sensor);
   173       }
   174 
   175       for (int i = 0; i < 2; i++) {
   176         Sensor sensor = miniNGControls[number * 2 + i];
   177         sensor.Value = data[offset + 15 + i];
   178         ActivateSensor(sensor);
   179       }
   180     }
   181 
   182     private void ReadData() {
   183       int[] data = new int[285];
   184       for (int i = 0; i < data.Length; i++)
   185         data[i] = FTD2XX.ReadByte(handle);
   186       
   187       if (data[0] != STARTFLAG) {
   188         FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX);   
   189         return;
   190       }
   191 
   192       if (data[1] == 255 || data[1] == 88) { // bigNG
   193 
   194         if (data[274] != protocolVersion) 
   195           return;
   196 
   197         this.primaryData = data;
   198 
   199         for (int i = 0; i < digitalTemperatures.Length; i++)
   200           if (data[238 + i] > 0) {
   201             digitalTemperatures[i].Value = 0.5f * data[238 + i] + 
   202               digitalTemperatures[i].Parameters[0].Value;
   203             ActivateSensor(digitalTemperatures[i]);
   204           } else {
   205             DeactivateSensor(digitalTemperatures[i]);
   206           }
   207 
   208         for (int i = 0; i < analogTemperatures.Length; i++)
   209           if (data[260 + i] > 0) {
   210             analogTemperatures[i].Value = 0.5f * data[260 + i] +
   211               analogTemperatures[i].Parameters[0].Value;
   212             ActivateSensor(analogTemperatures[i]);
   213           } else {
   214             DeactivateSensor(analogTemperatures[i]);
   215           }
   216 
   217         for (int i = 0; i < sensorhubTemperatures.Length; i++)
   218           if (data[246 + i] > 0) {
   219             sensorhubTemperatures[i].Value = 0.5f * data[246 + i] +
   220               sensorhubTemperatures[i].Parameters[0].Value;
   221             ActivateSensor(sensorhubTemperatures[i]);
   222           } else {
   223             DeactivateSensor(sensorhubTemperatures[i]);
   224           }
   225 
   226         for (int i = 0; i < sensorhubFlows.Length; i++)
   227           if (data[231 + i] > 0 && data[234] > 0) {
   228             float pulsesPerSecond = (data[231 + i] * 4.0f) / data[234];
   229             float pulsesPerLiter = sensorhubFlows[i].Parameters[0].Value;
   230             sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter;
   231             ActivateSensor(sensorhubFlows[i]);
   232           } else {
   233             DeactivateSensor(sensorhubFlows[i]);
   234           }
   235         
   236         for (int i = 0; i < fans.Length; i++) {
   237           float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]);
   238 
   239           if (fans[i] == null)
   240             fans[i] = new Sensor("Fan Channel " + i, i, SensorType.Fan,
   241               this, new ParameterDescription[] {
   242                 new ParameterDescription("MaxRPM", 
   243                   "Maximum revolutions per minute (RPM) of the fan.", maxRPM)
   244               });
   245 
   246           float value;
   247           if ((data[136] & (1 << i)) == 0)  // pwm mode
   248             value = 0.02f * data[137 + i];
   249           else // analog mode
   250             value = 0.01f * data[141 + i];
   251           
   252           fans[i].Value = fans[i].Parameters[0].Value * value;
   253           ActivateSensor(fans[i]);
   254 
   255           controls[i].Value = 100 * value;
   256           ActivateSensor(controls[i]);
   257         }
   258 
   259       } else if (data[1] == 253) { // miniNG #1
   260         this.alternativeData = data;
   261 
   262         ReadminiNG(data, 0);        
   263               
   264         if (data[66] == 253)  // miniNG #2
   265           ReadminiNG(data, 1);
   266       } 
   267     }
   268 
   269     public Image Icon {
   270       get { return icon; }
   271     }
   272 
   273     public string Name {
   274       get { return "T-Balancer bigNG"; }
   275     }
   276 
   277     public Identifier Identifier {
   278       get { return new Identifier("bigng", this.portIndex.ToString()); }
   279     }
   280 
   281     public IHardware[] SubHardware {
   282       get { return new IHardware[0]; }
   283     }
   284 
   285     public ISensor[] Sensors {
   286       get { return active.ToArray(); }
   287     }
   288 
   289     public string GetReport() {
   290       StringBuilder r = new StringBuilder();
   291 
   292       r.AppendLine("T-Balancer bigNG");
   293       r.AppendLine();
   294       r.Append("Port Index: "); r.AppendLine(portIndex.ToString());
   295       r.AppendLine();
   296 
   297       r.AppendLine("Primary System Information Answer");
   298       r.AppendLine();
   299       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   300       r.AppendLine();
   301       for (int i = 0; i <= 0x11; i++) {
   302         r.Append(" "); r.Append((i << 4).ToString("X3")); r.Append("  ");
   303         for (int j = 0; j <= 0xF; j++) {
   304           int index = ((i << 4) | j);
   305           if (index < primaryData.Length) {
   306             r.Append(" ");
   307             r.Append(primaryData[index].ToString("X2"));
   308           }          
   309         }
   310         r.AppendLine();
   311       }
   312       r.AppendLine();
   313 
   314       if (alternativeData.Length > 0) {
   315         r.AppendLine("Alternative System Information Answer");
   316         r.AppendLine();
   317         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   318         r.AppendLine();
   319         for (int i = 0; i <= 0x11; i++) {
   320           r.Append(" "); r.Append((i << 4).ToString("X3")); r.Append("  ");
   321           for (int j = 0; j <= 0xF; j++) {
   322             int index = ((i << 4) | j);
   323             if (index < alternativeData.Length) {
   324               r.Append(" ");
   325               r.Append(alternativeData[index].ToString("X2"));
   326             }
   327           }
   328           r.AppendLine();
   329         }
   330         r.AppendLine();
   331       }
   332 
   333       return r.ToString();
   334     }
   335 
   336     private void DelayedAlternativeRequest() {
   337       System.Threading.Thread.Sleep(500);      
   338       FTD2XX.Write(handle, new byte[] { 0x37 });
   339     }
   340 
   341     public void Open() {
   342       FTD2XX.FT_Open(portIndex, out handle); 
   343       FTD2XX.FT_SetBaudRate(handle, 19200);
   344       FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   345       FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   346         0x13);
   347       FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   348       FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   349     }
   350 
   351     public void Update() {
   352       while (FTD2XX.BytesToRead(handle) >= 285)
   353         ReadData();
   354       if (FTD2XX.BytesToRead(handle) == 1)
   355         FTD2XX.ReadByte(handle);
   356 
   357       FTD2XX.Write(handle, new byte[] { 0x38 });
   358       alternativeRequest.BeginInvoke(null, null);
   359     }
   360 
   361     public void Close() {
   362       FTD2XX.FT_Close(handle);
   363     }
   364 
   365     public event SensorEventHandler SensorAdded;
   366     public event SensorEventHandler SensorRemoved;
   367 
   368     public void Accept(IVisitor visitor) {
   369       visitor.VisitHardware(this);
   370     }
   371 
   372     public void Traverse(IVisitor visitor) { }
   373   }
   374 }