Hardware/TBalancer/TBalancer.cs
author moel.mich
Mon, 22 Feb 2010 20:54:49 +0000
changeset 61 cffcbf8a1401
parent 45 eadad41d21a6
child 63 1a7c13ac7348
permissions -rw-r--r--
NVAPI interop struct packing improved.
     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       int offset = 0;
    77       for (int i = 0; i < digitalTemperatures.Length; i++)
    78         digitalTemperatures[i] = new Sensor("Digital Sensor #" + (i + 1),
    79           offset + i, SensorType.Temperature, this);
    80       offset += digitalTemperatures.Length;
    81 
    82       for (int i = 0; i < analogTemperatures.Length; i++)
    83         analogTemperatures[i] = new Sensor("Analog Sensor #" + (i + 1),
    84           offset + i, SensorType.Temperature, this);
    85       offset += analogTemperatures.Length;
    86 
    87       for (int i = 0; i < sensorhubTemperatures.Length; i++)
    88         sensorhubTemperatures[i] = new Sensor("Sensorhub Sensor #" + (i + 1),
    89           offset + i, SensorType.Temperature, this);
    90       offset += sensorhubTemperatures.Length;
    91 
    92       for (int i = 0; i < sensorhubFlows.Length; i++)
    93         sensorhubFlows[i] = new Sensor("Flowmeter #" + (i + 1),
    94           offset + i, SensorType.Flow, this);
    95       offset += sensorhubFlows.Length;
    96 
    97       for (int i = 0; i < miniNGTemperatures.Length; i++)
    98         miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) + 
    99           " Sensor #" + (i % 2 + 1), offset + i, SensorType.Temperature, this);
   100       offset += miniNGTemperatures.Length;
   101 
   102       alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
   103 
   104       try {
   105         serialPort = new SerialPort(portName, 19200, Parity.None, 8,
   106           StopBits.One);
   107         serialPort.Open();
   108         Update();
   109       } catch (IOException) { }      
   110     }
   111 
   112     private void ActivateSensor(Sensor sensor) {
   113       deactivating.Remove(sensor);
   114       if (!active.Contains(sensor)) {
   115         active.Add(sensor);
   116         if (SensorAdded != null)
   117           SensorAdded(sensor);
   118       }      
   119     }
   120 
   121     private void DeactivateSensor(Sensor sensor) {
   122       if (deactivating.Contains(sensor)) {
   123         active.Remove(sensor);
   124         deactivating.Remove(sensor);
   125         if (SensorRemoved != null)
   126           SensorRemoved(sensor);
   127       } else if (active.Contains(sensor)) {
   128         deactivating.Add(sensor);
   129       }     
   130     }
   131 
   132     private void ReadminiNG(int[] data, int number) {
   133       int offset = 1 + number * 65;
   134 
   135       if (data[offset + 61] != ENDFLAG)
   136         return;
   137 
   138       for (int i = 0; i < 2; i++) {
   139         Sensor sensor = miniNGTemperatures[number * 2 + i];
   140         if (data[offset + 7 + i] > 0) {
   141           sensor.Value = 0.5f * data[offset + 7 + i];
   142           ActivateSensor(sensor);
   143         } else {
   144           DeactivateSensor(sensor);
   145         }
   146       }
   147 
   148       for (int i = 0; i < 2; i++) {
   149         float maxRPM = 20.0f * data[offset + 44 + 2 * i];
   150 
   151         if (miniNGFans[number * 2 + i] == null)
   152           miniNGFans[number * 2 + i] = 
   153             new Sensor("miniNG #" + (number + 1) + " Fan #" + (i + 1),
   154             4 + number * 2 + i, maxRPM, SensorType.Fan, this);
   155         
   156         Sensor sensor = miniNGFans[number * 2 + i];
   157 
   158         sensor.Value = 20.0f * data[offset + 43 + 2 * i];
   159         ActivateSensor(sensor);
   160       }
   161     }
   162 
   163     private void ReadData() {
   164       int[] data = new int[285];
   165       for (int i = 0; i < data.Length; i++)
   166         data[i] = serialPort.ReadByte();
   167 
   168       if (data[0] != STARTFLAG) {
   169         serialPort.DiscardInBuffer();   
   170         return;
   171       }
   172 
   173       if (data[1] == 255) { // bigNG
   174 
   175         if (data[274] != protocolVersion) 
   176           return;
   177 
   178         this.primaryData = data;
   179 
   180         for (int i = 0; i < digitalTemperatures.Length; i++)
   181           if (data[238 + i] > 0) {
   182             digitalTemperatures[i].Value = 0.5f * data[238 + i];
   183             ActivateSensor(digitalTemperatures[i]);
   184           } else {
   185             DeactivateSensor(digitalTemperatures[i]);
   186           }
   187 
   188         for (int i = 0; i < analogTemperatures.Length; i++)
   189           if (data[260 + i] > 0) {
   190             analogTemperatures[i].Value = 0.5f * data[260 + i];
   191             ActivateSensor(analogTemperatures[i]);
   192           } else {
   193             DeactivateSensor(analogTemperatures[i]);
   194           }
   195 
   196         for (int i = 0; i < sensorhubTemperatures.Length; i++)
   197           if (data[246 + i] > 0) {
   198             sensorhubTemperatures[i].Value = 0.5f * data[246 + i];
   199             ActivateSensor(sensorhubTemperatures[i]);
   200           } else {
   201             DeactivateSensor(sensorhubTemperatures[i]);
   202           }
   203 
   204         for (int i = 0; i < sensorhubFlows.Length; i++)
   205           if (data[231 + i] > 0 && data[234] > 0) {
   206             float pulsesPerSecond = ((float)data[231 + i]) / data[234];
   207             const float pulsesPerLiter = 509;
   208             sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter;
   209             ActivateSensor(sensorhubFlows[i]);
   210           } else {
   211             DeactivateSensor(sensorhubFlows[i]);
   212           }
   213 
   214         for (int i = 0; i < fans.Length; i++) {
   215           float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]);
   216 
   217           if (fans[i] == null)
   218             fans[i] = new Sensor("Fan #" + (i + 1), i, maxRPM, SensorType.Fan,
   219               this);
   220 
   221           if ((data[136] & (1 << i)) == 0)
   222             fans[i].Value = maxRPM * 0.01f * data[156 + i]; // pwm mode
   223           else
   224             fans[i].Value = maxRPM * 0.01f * data[141 + i]; // analog mode
   225           ActivateSensor(fans[i]);
   226         }
   227 
   228       } else if (data[1] == 253) { // miniNG #1
   229         this.alternativeData = data;
   230 
   231         ReadminiNG(data, 0);        
   232               
   233         if (data[66] == 252)  // miniNG #2
   234           ReadminiNG(data, 1);
   235       } 
   236     }
   237 
   238     public Image Icon {
   239       get { return icon; }
   240     }
   241 
   242     public string Name {
   243       get { return "T-Balancer bigNG"; }
   244     }
   245 
   246     public string Identifier {
   247       get { return "/bigng/" + 
   248         this.portName.TrimStart(new char[]{'/'}).ToLower(); }
   249     }
   250 
   251     public ISensor[] Sensors {
   252       get { return active.ToArray(); }
   253     }
   254 
   255     public string GetReport() {
   256       StringBuilder r = new StringBuilder();
   257 
   258       r.AppendLine("T-Balancer bigNG");
   259       r.AppendLine();
   260       r.Append("Port Name: "); r.AppendLine(serialPort.PortName);
   261       r.AppendLine();
   262 
   263       r.AppendLine("Primary System Information Answer");
   264       r.AppendLine();
   265       r.AppendLine("       00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   266       r.AppendLine();
   267       for (int i = 0; i <= 0x11; i++) {
   268         r.Append(" "); r.Append((i << 4).ToString("X3")); r.Append("  ");
   269         for (int j = 0; j <= 0xF; j++) {
   270           int index = ((i << 4) | j);
   271           if (index < primaryData.Length) {
   272             r.Append(" ");
   273             r.Append(primaryData[index].ToString("X2"));
   274           }          
   275         }
   276         r.AppendLine();
   277       }
   278       r.AppendLine();
   279 
   280       if (alternativeData.Length > 0) {
   281         r.AppendLine("Alternative 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 < alternativeData.Length) {
   290               r.Append(" ");
   291               r.Append(alternativeData[index].ToString("X2"));
   292             }
   293           }
   294           r.AppendLine();
   295         }
   296         r.AppendLine();
   297       }
   298 
   299       return r.ToString();
   300     }
   301 
   302     private void DelayedAlternativeRequest() {
   303       System.Threading.Thread.Sleep(500);
   304       try {
   305         if (serialPort.IsOpen)
   306           serialPort.Write(new byte[] { 0x37 }, 0, 1);
   307       } catch (Exception) { }
   308     }
   309 
   310     public void Update() {
   311       while (serialPort.BytesToRead >= 285)
   312         ReadData();
   313       if (serialPort.BytesToRead == 1)
   314         serialPort.ReadByte();
   315 
   316       serialPort.Write(new byte[] { 0x38 }, 0, 1);
   317       alternativeRequest.BeginInvoke(null, null);
   318     }
   319 
   320     public void Close() {
   321       serialPort.Close();
   322     }
   323 
   324     public event SensorEventHandler SensorAdded;
   325     public event SensorEventHandler SensorRemoved;
   326   }
   327 }