Hardware/TBalancer/TBalancer.cs
author moel.mich
Thu, 12 Aug 2010 20:53:27 +0000
changeset 166 fa9dfbfc4145
parent 165 813d8bc3192f
child 167 b7cc9d09aefe
permissions -rw-r--r--
Changed the project files to Visual Studio 2010. Fixed some Code Analysis warnings.
     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         float maxRPM = 20.0f * data[offset + 44 + 2 * i];
   165 
   166         if (miniNGFans[number * 2 + i] == null)
   167           miniNGFans[number * 2 + i] = 
   168             new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1),
   169             4 + number * 2 + i, SensorType.Fan, this, settings);
   170         
   171         Sensor sensor = miniNGFans[number * 2 + i];
   172 
   173         sensor.Value = 20.0f * data[offset + 43 + 2 * i];
   174         ActivateSensor(sensor);
   175       }
   176 
   177       for (int i = 0; i < 2; i++) {
   178         Sensor sensor = miniNGControls[number * 2 + i];
   179         sensor.Value = data[offset + 15 + i];
   180         ActivateSensor(sensor);
   181       }
   182     }
   183 
   184     private void ReadData() {
   185       int[] data = new int[285];
   186       for (int i = 0; i < data.Length; i++)
   187         data[i] = FTD2XX.ReadByte(handle);
   188       
   189       if (data[0] != STARTFLAG) {
   190         FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX);   
   191         return;
   192       }
   193 
   194       if (data[1] == 255 || data[1] == 88) { // bigNG
   195 
   196         if (data[274] != protocolVersion) 
   197           return;
   198 
   199         this.primaryData = data;
   200 
   201         for (int i = 0; i < digitalTemperatures.Length; i++)
   202           if (data[238 + i] > 0) {
   203             digitalTemperatures[i].Value = 0.5f * data[238 + i] + 
   204               digitalTemperatures[i].Parameters[0].Value;
   205             ActivateSensor(digitalTemperatures[i]);
   206           } else {
   207             DeactivateSensor(digitalTemperatures[i]);
   208           }
   209 
   210         for (int i = 0; i < analogTemperatures.Length; i++)
   211           if (data[260 + i] > 0) {
   212             analogTemperatures[i].Value = 0.5f * data[260 + i] +
   213               analogTemperatures[i].Parameters[0].Value;
   214             ActivateSensor(analogTemperatures[i]);
   215           } else {
   216             DeactivateSensor(analogTemperatures[i]);
   217           }
   218 
   219         for (int i = 0; i < sensorhubTemperatures.Length; i++)
   220           if (data[246 + i] > 0) {
   221             sensorhubTemperatures[i].Value = 0.5f * data[246 + i] +
   222               sensorhubTemperatures[i].Parameters[0].Value;
   223             ActivateSensor(sensorhubTemperatures[i]);
   224           } else {
   225             DeactivateSensor(sensorhubTemperatures[i]);
   226           }
   227 
   228         for (int i = 0; i < sensorhubFlows.Length; i++)
   229           if (data[231 + i] > 0 && data[234] > 0) {
   230             float pulsesPerSecond = (data[231 + i] * 4.0f) / data[234];
   231             float pulsesPerLiter = sensorhubFlows[i].Parameters[0].Value;
   232             sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter;
   233             ActivateSensor(sensorhubFlows[i]);
   234           } else {
   235             DeactivateSensor(sensorhubFlows[i]);
   236           }
   237         
   238         for (int i = 0; i < fans.Length; i++) {
   239           float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]);
   240 
   241           if (fans[i] == null)
   242             fans[i] = new Sensor("Fan Channel " + i, i, SensorType.Fan,
   243               this, new ParameterDescription[] {
   244                 new ParameterDescription("MaxRPM", 
   245                   "Maximum revolutions per minute (RPM) of the fan.", maxRPM)
   246               }, settings);
   247 
   248           float value;
   249           if ((data[136] & (1 << i)) == 0)  // pwm mode
   250             value = 0.02f * data[137 + i];
   251           else // analog mode
   252             value = 0.01f * data[141 + i];
   253           
   254           fans[i].Value = fans[i].Parameters[0].Value * value;
   255           ActivateSensor(fans[i]);
   256 
   257           controls[i].Value = 100 * value;
   258           ActivateSensor(controls[i]);
   259         }
   260 
   261       } else if (data[1] == 253) { // miniNG #1
   262         this.alternativeData = data;
   263 
   264         ReadminiNG(data, 0);        
   265               
   266         if (data[66] == 253)  // miniNG #2
   267           ReadminiNG(data, 1);
   268       } 
   269     }
   270 
   271     public HardwareType HardwareType {
   272       get { return HardwareType.TBalancer; }
   273     }
   274 
   275     public string Name {
   276       get { return "T-Balancer bigNG"; }
   277     }
   278 
   279     public Identifier Identifier {
   280       get { 
   281         return new Identifier("bigng",
   282           this.portIndex.ToString(CultureInfo.InvariantCulture));
   283       }
   284     }
   285 
   286     public IHardware[] SubHardware {
   287       get { return new IHardware[0]; }
   288     }
   289 
   290     public ISensor[] Sensors {
   291       get { return active.ToArray(); }
   292     }
   293 
   294     public string GetReport() {
   295       StringBuilder r = new StringBuilder();
   296 
   297       r.AppendLine("T-Balancer bigNG");
   298       r.AppendLine();
   299       r.Append("Port Index: "); 
   300       r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture));
   301       r.AppendLine();
   302 
   303       r.AppendLine("Primary System Information Answer");
   304       r.AppendLine();
   305       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   306       r.AppendLine();
   307       for (int i = 0; i <= 0x11; i++) {
   308         r.Append(" "); 
   309         r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   310         r.Append("  ");
   311         for (int j = 0; j <= 0xF; j++) {
   312           int index = ((i << 4) | j);
   313           if (index < primaryData.Length) {
   314             r.Append(" ");
   315             r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture));
   316           }          
   317         }
   318         r.AppendLine();
   319       }
   320       r.AppendLine();
   321 
   322       if (alternativeData.Length > 0) {
   323         r.AppendLine("Alternative System Information Answer");
   324         r.AppendLine();
   325         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   326         r.AppendLine();
   327         for (int i = 0; i <= 0x11; i++) {
   328           r.Append(" "); 
   329           r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); 
   330           r.Append("  ");
   331           for (int j = 0; j <= 0xF; j++) {
   332             int index = ((i << 4) | j);
   333             if (index < alternativeData.Length) {
   334               r.Append(" ");
   335               r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture));
   336             }
   337           }
   338           r.AppendLine();
   339         }
   340         r.AppendLine();
   341       }
   342 
   343       return r.ToString();
   344     }
   345 
   346     private void DelayedAlternativeRequest() {
   347       System.Threading.Thread.Sleep(500);      
   348       FTD2XX.Write(handle, new byte[] { 0x37 });
   349     }
   350 
   351     public void Open() {
   352       FTD2XX.FT_Open(portIndex, out handle); 
   353       FTD2XX.FT_SetBaudRate(handle, 19200);
   354       FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   355       FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   356         0x13);
   357       FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   358       FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   359     }
   360 
   361     public void Update() {
   362       while (FTD2XX.BytesToRead(handle) >= 285)
   363         ReadData();
   364       if (FTD2XX.BytesToRead(handle) == 1)
   365         FTD2XX.ReadByte(handle);
   366 
   367       FTD2XX.Write(handle, new byte[] { 0x38 });
   368       alternativeRequest.BeginInvoke(null, null);
   369     }
   370 
   371     public void Close() {
   372       FTD2XX.FT_Close(handle);
   373     }
   374 
   375     public event SensorEventHandler SensorAdded;
   376     public event SensorEventHandler SensorRemoved;
   377 
   378     public void Accept(IVisitor visitor) {
   379       if (visitor != null)
   380         visitor.VisitHardware(this);
   381     }
   382 
   383     public void Traverse(IVisitor visitor) { }
   384   }
   385 }