Hardware/TBalancer/TBalancer.cs
author paulwerelds
Tue, 05 Oct 2010 19:34:59 +0000
changeset 213 d93c927e4fd6
parent 182 4801e9eaf979
child 275 35788ddd1825
permissions -rw-r--r--
Fixed Issue 123.
     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.Globalization;
    41 using System.Text;
    42 
    43 namespace OpenHardwareMonitor.Hardware.TBalancer {
    44   internal class TBalancer : IHardware {
    45 
    46     private readonly ISettings settings;
    47     private readonly int portIndex;    
    48     private readonly byte protocolVersion;
    49     private readonly Sensor[] digitalTemperatures = new Sensor[8];
    50     private readonly Sensor[] analogTemperatures = new Sensor[4];
    51     private readonly Sensor[] sensorhubTemperatures = new Sensor[6];
    52     private readonly Sensor[] sensorhubFlows = new Sensor[2];
    53     private readonly Sensor[] fans = new Sensor[4];
    54     private readonly Sensor[] controls = new Sensor[4];
    55     private readonly Sensor[] miniNGTemperatures = new Sensor[4];
    56     private readonly Sensor[] miniNGFans = new Sensor[4];
    57     private readonly Sensor[] miniNGControls = new Sensor[4];
    58     private readonly List<ISensor> active = new List<ISensor>();
    59     private readonly List<ISensor> deactivating = new List<ISensor>();
    60 
    61     private FT_HANDLE handle;
    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 readonly 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 [] {
    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 [] {
   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 [] { new ParameterDescription("MaxRPM", 
   242                   "Maximum revolutions per minute (RPM) of the fan.", maxRPM)
   243               }, settings);
   244 
   245           float value;
   246           if ((data[136] & (1 << i)) == 0)  // pwm mode
   247             value = 0.02f * data[137 + i];
   248           else // analog mode
   249             value = 0.01f * data[141 + i];
   250           
   251           fans[i].Value = fans[i].Parameters[0].Value * value;
   252           ActivateSensor(fans[i]);
   253 
   254           controls[i].Value = 100 * value;
   255           ActivateSensor(controls[i]);
   256         }
   257 
   258       } else if (data[1] == 253) { // miniNG #1
   259         this.alternativeData = data;
   260 
   261         ReadminiNG(data, 0);        
   262               
   263         if (data[66] == 253)  // miniNG #2
   264           ReadminiNG(data, 1);
   265       } 
   266     }
   267 
   268     public HardwareType HardwareType {
   269       get { return HardwareType.TBalancer; }
   270     }
   271 
   272     public string Name {
   273       get { return "T-Balancer bigNG"; }
   274     }
   275 
   276     public Identifier Identifier {
   277       get { 
   278         return new Identifier("bigng",
   279           this.portIndex.ToString(CultureInfo.InvariantCulture));
   280       }
   281     }
   282 
   283     public IHardware[] SubHardware {
   284       get { return new IHardware[0]; }
   285     }
   286 
   287     public virtual IHardware Parent {
   288       get { return null; }
   289     }
   290 
   291     public ISensor[] Sensors {
   292       get { return active.ToArray(); }
   293     }
   294 
   295     public string GetReport() {
   296       StringBuilder r = new StringBuilder();
   297 
   298       r.AppendLine("T-Balancer bigNG");
   299       r.AppendLine();
   300       r.Append("Port Index: "); 
   301       r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture));
   302       r.AppendLine();
   303 
   304       r.AppendLine("Primary System Information Answer");
   305       r.AppendLine();
   306       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   307       r.AppendLine();
   308       for (int i = 0; i <= 0x11; i++) {
   309         r.Append(" "); 
   310         r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   311         r.Append("  ");
   312         for (int j = 0; j <= 0xF; j++) {
   313           int index = ((i << 4) | j);
   314           if (index < primaryData.Length) {
   315             r.Append(" ");
   316             r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture));
   317           }          
   318         }
   319         r.AppendLine();
   320       }
   321       r.AppendLine();
   322 
   323       if (alternativeData.Length > 0) {
   324         r.AppendLine("Alternative System Information Answer");
   325         r.AppendLine();
   326         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   327         r.AppendLine();
   328         for (int i = 0; i <= 0x11; i++) {
   329           r.Append(" "); 
   330           r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   331           r.Append("  ");
   332           for (int j = 0; j <= 0xF; j++) {
   333             int index = ((i << 4) | j);
   334             if (index < alternativeData.Length) {
   335               r.Append(" ");
   336               r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture));
   337             }
   338           }
   339           r.AppendLine();
   340         }
   341         r.AppendLine();
   342       }
   343 
   344       return r.ToString();
   345     }
   346 
   347     private void DelayedAlternativeRequest() {
   348       System.Threading.Thread.Sleep(500);      
   349       FTD2XX.Write(handle, new byte[] { 0x37 });
   350     }
   351 
   352     public void Open() {
   353       FTD2XX.FT_Open(portIndex, out handle); 
   354       FTD2XX.FT_SetBaudRate(handle, 19200);
   355       FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   356       FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   357         0x13);
   358       FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   359       FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   360     }
   361 
   362     public void Update() {
   363       while (FTD2XX.BytesToRead(handle) >= 285)
   364         ReadData();
   365       if (FTD2XX.BytesToRead(handle) == 1)
   366         FTD2XX.ReadByte(handle);
   367 
   368       FTD2XX.Write(handle, new byte[] { 0x38 });
   369       alternativeRequest.BeginInvoke(null, null);
   370     }
   371 
   372     public void Close() {
   373       FTD2XX.FT_Close(handle);
   374     }
   375 
   376     public event SensorEventHandler SensorAdded;
   377     public event SensorEventHandler SensorRemoved;
   378 
   379     public void Accept(IVisitor visitor) {
   380       if (visitor == null)
   381         throw new ArgumentNullException("visitor");
   382       visitor.VisitHardware(this);
   383     }
   384 
   385     public void Traverse(IVisitor visitor) { }
   386   }
   387 }