Hardware/TBalancer/TBalancer.cs
author moel.mich
Tue, 24 Aug 2010 22:11:10 +0000
changeset 175 e4ee19d583bd
parent 166 fa9dfbfc4145
child 176 c16fd81b520a
permissions -rw-r--r--
Search all possible registry locations for the Heatmaster serial port.
     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.Globalization;
    42 using System.Text;
    43 
    44 namespace OpenHardwareMonitor.Hardware.TBalancer {
    45   internal class TBalancer : IHardware {
    46 
    47     private ISettings settings;
    48     private int portIndex;
    49     private FT_HANDLE handle;
    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, ISettings settings) {
    72       this.settings = settings;
    73 
    74       this.portIndex = portIndex;
    75       this.protocolVersion = protocolVersion;
    76 
    77       ParameterDescription[] parameter = new ParameterDescription[] {
    78         new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
    79       };
    80       int offset = 0;
    81       for (int i = 0; i < digitalTemperatures.Length; i++)
    82         digitalTemperatures[i] = new Sensor("Digital Sensor " + i,
    83           offset + i, SensorType.Temperature, this, parameter, settings);
    84       offset += digitalTemperatures.Length;
    85 
    86       for (int i = 0; i < analogTemperatures.Length; i++)
    87         analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1),
    88           offset + i, SensorType.Temperature, this, parameter, settings);
    89       offset += analogTemperatures.Length;
    90 
    91       for (int i = 0; i < sensorhubTemperatures.Length; i++)
    92         sensorhubTemperatures[i] = new Sensor("Sensorhub Sensor " + i,
    93           offset + i, SensorType.Temperature, this, parameter, settings);
    94       offset += sensorhubTemperatures.Length;
    95 
    96       for (int i = 0; i < miniNGTemperatures.Length; i++)
    97         miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) +
    98           " Sensor " + (i % 2 + 1), offset + i, SensorType.Temperature,
    99           this, parameter, settings);
   100       offset += miniNGTemperatures.Length;
   101 
   102       for (int i = 0; i < sensorhubFlows.Length; i++)
   103         sensorhubFlows[i] = new Sensor("Flowmeter " + (i + 1),
   104           i, SensorType.Flow, this, new ParameterDescription[] {
   105             new ParameterDescription("Impulse Rate", 
   106               "The impulse rate of the flowmeter in pulses/L", 509)
   107           }, settings);
   108 
   109       for (int i = 0; i < controls.Length; i++) {
   110         controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, 
   111           this, settings);
   112       }
   113 
   114       for (int i = 0; i < miniNGControls.Length; i++) {
   115         miniNGControls[i] = new Sensor("miniNG #" + (i / 2 + 1) +
   116           " Fan Channel " + (i % 2 + 1), 4 + i, SensorType.Control, this, 
   117           settings);
   118       }
   119 
   120       alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
   121 
   122       Open();
   123       Update(); 
   124     }
   125 
   126     private void ActivateSensor(Sensor sensor) {
   127       deactivating.Remove(sensor);
   128       if (!active.Contains(sensor)) {
   129         active.Add(sensor);
   130         if (SensorAdded != null)
   131           SensorAdded(sensor);
   132       }      
   133     }
   134 
   135     private void DeactivateSensor(Sensor sensor) {
   136       if (deactivating.Contains(sensor)) {
   137         active.Remove(sensor);
   138         deactivating.Remove(sensor);
   139         if (SensorRemoved != null)
   140           SensorRemoved(sensor);
   141       } else if (active.Contains(sensor)) {
   142         deactivating.Add(sensor);
   143       }     
   144     }
   145 
   146     private void ReadminiNG(int[] data, int number) {
   147       int offset = 1 + number * 65;
   148 
   149       if (data[offset + 61] != ENDFLAG)
   150         return;
   151 
   152       for (int i = 0; i < 2; i++) {
   153         Sensor sensor = miniNGTemperatures[number * 2 + i];
   154         if (data[offset + 7 + i] > 0) {
   155           sensor.Value = 0.5f * data[offset + 7 + i] + 
   156             sensor.Parameters[0].Value;
   157           ActivateSensor(sensor);
   158         } else {
   159           DeactivateSensor(sensor);
   160         }
   161       }
   162 
   163       for (int i = 0; i < 2; i++) {
   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, settings);
   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               }, settings);
   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 HardwareType HardwareType {
   270       get { return HardwareType.TBalancer; }
   271     }
   272 
   273     public string Name {
   274       get { return "T-Balancer bigNG"; }
   275     }
   276 
   277     public Identifier Identifier {
   278       get { 
   279         return new Identifier("bigng",
   280           this.portIndex.ToString(CultureInfo.InvariantCulture));
   281       }
   282     }
   283 
   284     public IHardware[] SubHardware {
   285       get { return new IHardware[0]; }
   286     }
   287 
   288     public ISensor[] Sensors {
   289       get { return active.ToArray(); }
   290     }
   291 
   292     public string GetReport() {
   293       StringBuilder r = new StringBuilder();
   294 
   295       r.AppendLine("T-Balancer bigNG");
   296       r.AppendLine();
   297       r.Append("Port Index: "); 
   298       r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture));
   299       r.AppendLine();
   300 
   301       r.AppendLine("Primary System Information Answer");
   302       r.AppendLine();
   303       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   304       r.AppendLine();
   305       for (int i = 0; i <= 0x11; i++) {
   306         r.Append(" "); 
   307         r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   308         r.Append("  ");
   309         for (int j = 0; j <= 0xF; j++) {
   310           int index = ((i << 4) | j);
   311           if (index < primaryData.Length) {
   312             r.Append(" ");
   313             r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture));
   314           }          
   315         }
   316         r.AppendLine();
   317       }
   318       r.AppendLine();
   319 
   320       if (alternativeData.Length > 0) {
   321         r.AppendLine("Alternative System Information Answer");
   322         r.AppendLine();
   323         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   324         r.AppendLine();
   325         for (int i = 0; i <= 0x11; i++) {
   326           r.Append(" "); 
   327           r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   328           r.Append("  ");
   329           for (int j = 0; j <= 0xF; j++) {
   330             int index = ((i << 4) | j);
   331             if (index < alternativeData.Length) {
   332               r.Append(" ");
   333               r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture));
   334             }
   335           }
   336           r.AppendLine();
   337         }
   338         r.AppendLine();
   339       }
   340 
   341       return r.ToString();
   342     }
   343 
   344     private void DelayedAlternativeRequest() {
   345       System.Threading.Thread.Sleep(500);      
   346       FTD2XX.Write(handle, new byte[] { 0x37 });
   347     }
   348 
   349     public void Open() {
   350       FTD2XX.FT_Open(portIndex, out handle); 
   351       FTD2XX.FT_SetBaudRate(handle, 19200);
   352       FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   353       FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   354         0x13);
   355       FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   356       FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   357     }
   358 
   359     public void Update() {
   360       while (FTD2XX.BytesToRead(handle) >= 285)
   361         ReadData();
   362       if (FTD2XX.BytesToRead(handle) == 1)
   363         FTD2XX.ReadByte(handle);
   364 
   365       FTD2XX.Write(handle, new byte[] { 0x38 });
   366       alternativeRequest.BeginInvoke(null, null);
   367     }
   368 
   369     public void Close() {
   370       FTD2XX.FT_Close(handle);
   371     }
   372 
   373     public event SensorEventHandler SensorAdded;
   374     public event SensorEventHandler SensorRemoved;
   375 
   376     public void Accept(IVisitor visitor) {
   377       if (visitor == null)
   378         throw new ArgumentNullException("visitor");
   379       visitor.VisitHardware(this);
   380     }
   381 
   382     public void Traverse(IVisitor visitor) { }
   383   }
   384 }