Hardware/TBalancer/TBalancer.cs
author moel.mich
Mon, 06 Sep 2010 19:53:13 +0000
changeset 176 c16fd81b520a
parent 167 b7cc9d09aefe
child 182 4801e9eaf979
permissions -rw-r--r--
Added a desktop gadget implementation.
     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 virtual IHardware Parent {
   289       get { return null; }
   290     }
   291 
   292     public ISensor[] Sensors {
   293       get { return active.ToArray(); }
   294     }
   295 
   296     public string GetReport() {
   297       StringBuilder r = new StringBuilder();
   298 
   299       r.AppendLine("T-Balancer bigNG");
   300       r.AppendLine();
   301       r.Append("Port Index: "); 
   302       r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture));
   303       r.AppendLine();
   304 
   305       r.AppendLine("Primary System Information Answer");
   306       r.AppendLine();
   307       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   308       r.AppendLine();
   309       for (int i = 0; i <= 0x11; i++) {
   310         r.Append(" "); 
   311         r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   312         r.Append("  ");
   313         for (int j = 0; j <= 0xF; j++) {
   314           int index = ((i << 4) | j);
   315           if (index < primaryData.Length) {
   316             r.Append(" ");
   317             r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture));
   318           }          
   319         }
   320         r.AppendLine();
   321       }
   322       r.AppendLine();
   323 
   324       if (alternativeData.Length > 0) {
   325         r.AppendLine("Alternative System Information Answer");
   326         r.AppendLine();
   327         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   328         r.AppendLine();
   329         for (int i = 0; i <= 0x11; i++) {
   330           r.Append(" "); 
   331           r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   332           r.Append("  ");
   333           for (int j = 0; j <= 0xF; j++) {
   334             int index = ((i << 4) | j);
   335             if (index < alternativeData.Length) {
   336               r.Append(" ");
   337               r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture));
   338             }
   339           }
   340           r.AppendLine();
   341         }
   342         r.AppendLine();
   343       }
   344 
   345       return r.ToString();
   346     }
   347 
   348     private void DelayedAlternativeRequest() {
   349       System.Threading.Thread.Sleep(500);      
   350       FTD2XX.Write(handle, new byte[] { 0x37 });
   351     }
   352 
   353     public void Open() {
   354       FTD2XX.FT_Open(portIndex, out handle); 
   355       FTD2XX.FT_SetBaudRate(handle, 19200);
   356       FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   357       FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   358         0x13);
   359       FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   360       FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   361     }
   362 
   363     public void Update() {
   364       while (FTD2XX.BytesToRead(handle) >= 285)
   365         ReadData();
   366       if (FTD2XX.BytesToRead(handle) == 1)
   367         FTD2XX.ReadByte(handle);
   368 
   369       FTD2XX.Write(handle, new byte[] { 0x38 });
   370       alternativeRequest.BeginInvoke(null, null);
   371     }
   372 
   373     public void Close() {
   374       FTD2XX.FT_Close(handle);
   375     }
   376 
   377     public event SensorEventHandler SensorAdded;
   378     public event SensorEventHandler SensorRemoved;
   379 
   380     public void Accept(IVisitor visitor) {
   381       if (visitor == null)
   382         throw new ArgumentNullException("visitor");
   383       visitor.VisitHardware(this);
   384     }
   385 
   386     public void Traverse(IVisitor visitor) { }
   387   }
   388 }