Hardware/TBalancer/TBalancer.cs
author moel.mich
Mon, 22 Mar 2010 17:58:21 +0000
changeset 81 7f4079703ab0
parent 73 8296f0ba87b1
child 83 3fdadd4a830f
permissions -rw-r--r--
Fixed Issue 21.
     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.IO;
    43 using System.IO.Ports;
    44 using System.Text;
    45 
    46 namespace OpenHardwareMonitor.Hardware.TBalancer {
    47   public class TBalancer : IHardware {
    48 
    49     private string portName;
    50     private Image icon;
    51     private SerialPort serialPort;
    52     private byte protocolVersion;
    53     private Sensor[] digitalTemperatures = new Sensor[8];
    54     private Sensor[] analogTemperatures = new Sensor[4];
    55     private Sensor[] sensorhubTemperatures = new Sensor[6];
    56     private Sensor[] sensorhubFlows = new Sensor[2];
    57     private Sensor[] fans = new Sensor[4];
    58     private Sensor[] miniNGTemperatures = new Sensor[4];
    59     private Sensor[] miniNGFans = 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(string portName, byte protocolVersion) {
    72       this.portName = portName;
    73       this.icon = Utilities.EmbeddedResources.GetImage("bigng.png");
    74       this.protocolVersion = protocolVersion;
    75 
    76       ParameterDescription[] parameter = new ParameterDescription[] {
    77         new ParameterDescription("Offset", "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 + 1),
    82           offset + i, null, 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, null, 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 + 1),
    92           offset + i, null, SensorType.Temperature, this, parameter);
    93       offset += sensorhubTemperatures.Length;
    94 
    95       for (int i = 0; i < sensorhubFlows.Length; i++)
    96         sensorhubFlows[i] = new Sensor("Flowmeter #" + (i + 1),
    97           offset + i, null, SensorType.Flow, this, new ParameterDescription[] {
    98             new ParameterDescription("Impulse Rate", 
    99               "The impulse rate of the flowmeter in pulses/L", 509)
   100           });
   101       offset += sensorhubFlows.Length;
   102 
   103       for (int i = 0; i < miniNGTemperatures.Length; i++)
   104         miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) +
   105           " Sensor #" + (i % 2 + 1), offset + i, null, SensorType.Temperature, 
   106           this, parameter);
   107       offset += miniNGTemperatures.Length;
   108 
   109       alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
   110 
   111       try {
   112         serialPort = new SerialPort(portName, 19200, Parity.None, 8,
   113           StopBits.One);
   114         serialPort.Open();
   115         Update();
   116       } catch (IOException) { }      
   117     }
   118 
   119     private void ActivateSensor(Sensor sensor) {
   120       deactivating.Remove(sensor);
   121       if (!active.Contains(sensor)) {
   122         active.Add(sensor);
   123         if (SensorAdded != null)
   124           SensorAdded(sensor);
   125       }      
   126     }
   127 
   128     private void DeactivateSensor(Sensor sensor) {
   129       if (deactivating.Contains(sensor)) {
   130         active.Remove(sensor);
   131         deactivating.Remove(sensor);
   132         if (SensorRemoved != null)
   133           SensorRemoved(sensor);
   134       } else if (active.Contains(sensor)) {
   135         deactivating.Add(sensor);
   136       }     
   137     }
   138 
   139     private void ReadminiNG(int[] data, int number) {
   140       int offset = 1 + number * 65;
   141 
   142       if (data[offset + 61] != ENDFLAG)
   143         return;
   144 
   145       for (int i = 0; i < 2; i++) {
   146         Sensor sensor = miniNGTemperatures[number * 2 + i];
   147         if (data[offset + 7 + i] > 0) {
   148           sensor.Value = 0.5f * data[offset + 7 + i] + 
   149             sensor.Parameters[0].Value;
   150           ActivateSensor(sensor);
   151         } else {
   152           DeactivateSensor(sensor);
   153         }
   154       }
   155 
   156       for (int i = 0; i < 2; i++) {
   157         float maxRPM = 20.0f * data[offset + 44 + 2 * i];
   158 
   159         if (miniNGFans[number * 2 + i] == null)
   160           miniNGFans[number * 2 + i] = 
   161             new Sensor("miniNG #" + (number + 1) + " Fan #" + (i + 1),
   162             4 + number * 2 + i, maxRPM, SensorType.Fan, this);
   163         
   164         Sensor sensor = miniNGFans[number * 2 + i];
   165 
   166         sensor.Value = 20.0f * data[offset + 43 + 2 * i];
   167         ActivateSensor(sensor);
   168       }
   169     }
   170 
   171     private void ReadData() {
   172       int[] data = new int[285];
   173       for (int i = 0; i < data.Length; i++)
   174         data[i] = serialPort.ReadByte();
   175 
   176       if (data[0] != STARTFLAG) {
   177         serialPort.DiscardInBuffer();   
   178         return;
   179       }
   180 
   181       if (data[1] == 255 || data[1] == 88) { // bigNG
   182 
   183         if (data[274] != protocolVersion) 
   184           return;
   185 
   186         this.primaryData = data;
   187 
   188         for (int i = 0; i < digitalTemperatures.Length; i++)
   189           if (data[238 + i] > 0) {
   190             digitalTemperatures[i].Value = 0.5f * data[238 + i] + 
   191               digitalTemperatures[i].Parameters[0].Value;
   192             ActivateSensor(digitalTemperatures[i]);
   193           } else {
   194             DeactivateSensor(digitalTemperatures[i]);
   195           }
   196 
   197         for (int i = 0; i < analogTemperatures.Length; i++)
   198           if (data[260 + i] > 0) {
   199             analogTemperatures[i].Value = 0.5f * data[260 + i] +
   200               analogTemperatures[i].Parameters[0].Value;
   201             ActivateSensor(analogTemperatures[i]);
   202           } else {
   203             DeactivateSensor(analogTemperatures[i]);
   204           }
   205 
   206         for (int i = 0; i < sensorhubTemperatures.Length; i++)
   207           if (data[246 + i] > 0) {
   208             sensorhubTemperatures[i].Value = 0.5f * data[246 + i] +
   209               sensorhubTemperatures[i].Parameters[0].Value;
   210             ActivateSensor(sensorhubTemperatures[i]);
   211           } else {
   212             DeactivateSensor(sensorhubTemperatures[i]);
   213           }
   214 
   215         for (int i = 0; i < sensorhubFlows.Length; i++)
   216           if (data[231 + i] > 0 && data[234] > 0) {
   217             float pulsesPerSecond = (data[231 + i] * 4.0f) / data[234];
   218             float pulsesPerLiter = sensorhubFlows[i].Parameters[0].Value;
   219             sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter;
   220             ActivateSensor(sensorhubFlows[i]);
   221           } else {
   222             DeactivateSensor(sensorhubFlows[i]);
   223           }
   224 
   225         for (int i = 0; i < fans.Length; i++) {
   226           float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]);
   227 
   228           if (fans[i] == null)
   229             fans[i] = new Sensor("Fan #" + (i + 1), i, maxRPM, SensorType.Fan,
   230               this, new ParameterDescription[] {
   231                 new ParameterDescription("MaxRPM", 
   232                   "Maximum revolutions per minute (RPM) of the fan.", maxRPM)
   233               });
   234 
   235           if ((data[136] & (1 << i)) == 0) // pwm mode
   236             fans[i].Value = fans[i].Parameters[0].Value * 0.02f * data[137 + i];
   237           else // analog mode
   238             fans[i].Value = fans[i].Parameters[0].Value * 0.01f * data[141 + i]; 
   239           ActivateSensor(fans[i]);
   240         }
   241 
   242       } else if (data[1] == 253) { // miniNG #1
   243         this.alternativeData = data;
   244 
   245         ReadminiNG(data, 0);        
   246               
   247         if (data[66] == 252)  // miniNG #2
   248           ReadminiNG(data, 1);
   249       } 
   250     }
   251 
   252     public Image Icon {
   253       get { return icon; }
   254     }
   255 
   256     public string Name {
   257       get { return "T-Balancer bigNG"; }
   258     }
   259 
   260     public string Identifier {
   261       get { return "/bigng/" + 
   262         this.portName.TrimStart(new char[]{'/'}).ToLower(); }
   263     }
   264 
   265     public IHardware[] SubHardware {
   266       get { return new IHardware[0]; }
   267     }
   268 
   269     public ISensor[] Sensors {
   270       get { return active.ToArray(); }
   271     }
   272 
   273     public string GetReport() {
   274       StringBuilder r = new StringBuilder();
   275 
   276       r.AppendLine("T-Balancer bigNG");
   277       r.AppendLine();
   278       r.Append("Port Name: "); r.AppendLine(serialPort.PortName);
   279       r.AppendLine();
   280 
   281       r.AppendLine("Primary System Information Answer");
   282       r.AppendLine();
   283       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   284       r.AppendLine();
   285       for (int i = 0; i <= 0x11; i++) {
   286         r.Append(" "); r.Append((i << 4).ToString("X3")); r.Append("  ");
   287         for (int j = 0; j <= 0xF; j++) {
   288           int index = ((i << 4) | j);
   289           if (index < primaryData.Length) {
   290             r.Append(" ");
   291             r.Append(primaryData[index].ToString("X2"));
   292           }          
   293         }
   294         r.AppendLine();
   295       }
   296       r.AppendLine();
   297 
   298       if (alternativeData.Length > 0) {
   299         r.AppendLine("Alternative System Information Answer");
   300         r.AppendLine();
   301         r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   302         r.AppendLine();
   303         for (int i = 0; i <= 0x11; i++) {
   304           r.Append(" "); r.Append((i << 4).ToString("X3")); r.Append("  ");
   305           for (int j = 0; j <= 0xF; j++) {
   306             int index = ((i << 4) | j);
   307             if (index < alternativeData.Length) {
   308               r.Append(" ");
   309               r.Append(alternativeData[index].ToString("X2"));
   310             }
   311           }
   312           r.AppendLine();
   313         }
   314         r.AppendLine();
   315       }
   316 
   317       return r.ToString();
   318     }
   319 
   320     private void DelayedAlternativeRequest() {
   321       System.Threading.Thread.Sleep(500);
   322       try {
   323         if (serialPort.IsOpen)
   324           serialPort.Write(new byte[] { 0x37 }, 0, 1);
   325       } catch (Exception) { }
   326     }
   327 
   328     public void Update() {
   329       while (serialPort.BytesToRead >= 285)
   330         ReadData();
   331       if (serialPort.BytesToRead == 1)
   332         serialPort.ReadByte();
   333 
   334       serialPort.Write(new byte[] { 0x38 }, 0, 1);
   335       alternativeRequest.BeginInvoke(null, null);
   336     }
   337 
   338     public void Close() {
   339       serialPort.Close();
   340     }
   341 
   342     public event SensorEventHandler SensorAdded;
   343     public event SensorEventHandler SensorRemoved;
   344   }
   345 }