moel@1: /* moel@1: moel@1: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@1: moel@1: The contents of this file are subject to the Mozilla Public License Version moel@1: 1.1 (the "License"); you may not use this file except in compliance with moel@1: the License. You may obtain a copy of the License at moel@1: moel@1: http://www.mozilla.org/MPL/ moel@1: moel@1: Software distributed under the License is distributed on an "AS IS" basis, moel@1: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@1: for the specific language governing rights and limitations under the License. moel@1: moel@1: The Original Code is the Open Hardware Monitor code. moel@1: moel@1: The Initial Developer of the Original Code is moel@1: Michael Möller . moel@1: Portions created by the Initial Developer are Copyright (C) 2009-2010 moel@1: the Initial Developer. All Rights Reserved. moel@1: moel@1: Contributor(s): moel@1: moel@1: Alternatively, the contents of this file may be used under the terms of moel@1: either the GNU General Public License Version 2 or later (the "GPL"), or moel@1: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@1: in which case the provisions of the GPL or the LGPL are applicable instead moel@1: of those above. If you wish to allow use of your version of this file only moel@1: under the terms of either the GPL or the LGPL, and not to allow others to moel@1: use your version of this file under the terms of the MPL, indicate your moel@1: decision by deleting the provisions above and replace them with the notice moel@1: and other provisions required by the GPL or the LGPL. If you do not delete moel@1: the provisions above, a recipient may use your version of this file under moel@1: the terms of any one of the MPL, the GPL or the LGPL. moel@1: moel@1: */ moel@1: moel@1: using System; moel@1: using System.Collections.Generic; moel@1: using System.Configuration; moel@166: using System.Globalization; moel@1: using System.Text; moel@1: moel@1: namespace OpenHardwareMonitor.Hardware.TBalancer { moel@165: internal class TBalancer : IHardware { moel@1: moel@165: private ISettings settings; moel@87: private int portIndex; moel@87: private FT_HANDLE handle; moel@33: private byte protocolVersion; moel@1: private Sensor[] digitalTemperatures = new Sensor[8]; moel@1: private Sensor[] analogTemperatures = new Sensor[4]; moel@57: private Sensor[] sensorhubTemperatures = new Sensor[6]; moel@57: private Sensor[] sensorhubFlows = new Sensor[2]; moel@1: private Sensor[] fans = new Sensor[4]; moel@118: private Sensor[] controls = new Sensor[4]; moel@57: private Sensor[] miniNGTemperatures = new Sensor[4]; moel@57: private Sensor[] miniNGFans = new Sensor[4]; moel@137: private Sensor[] miniNGControls = new Sensor[4]; moel@1: private List active = new List(); moel@1: private List deactivating = new List(); moel@57: private int[] primaryData = new int[0]; moel@57: private int[] alternativeData = new int[0]; moel@1: moel@1: public const byte STARTFLAG = 100; moel@57: public const byte ENDFLAG = 254; moel@57: moel@57: private delegate void MethodDelegate(); moel@57: private MethodDelegate alternativeRequest; moel@1: moel@165: public TBalancer(int portIndex, byte protocolVersion, ISettings settings) { moel@165: this.settings = settings; moel@165: moel@87: this.portIndex = portIndex; moel@33: this.protocolVersion = protocolVersion; moel@1: moel@63: ParameterDescription[] parameter = new ParameterDescription[] { moel@122: new ParameterDescription("Offset [°C]", "Temperature offset.", 0) moel@63: }; moel@57: int offset = 0; moel@57: for (int i = 0; i < digitalTemperatures.Length; i++) moel@88: digitalTemperatures[i] = new Sensor("Digital Sensor " + i, moel@165: offset + i, SensorType.Temperature, this, parameter, settings); moel@57: offset += digitalTemperatures.Length; moel@57: moel@57: for (int i = 0; i < analogTemperatures.Length; i++) moel@88: analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1), moel@165: offset + i, SensorType.Temperature, this, parameter, settings); moel@57: offset += analogTemperatures.Length; moel@57: moel@57: for (int i = 0; i < sensorhubTemperatures.Length; i++) moel@88: sensorhubTemperatures[i] = new Sensor("Sensorhub Sensor " + i, moel@165: offset + i, SensorType.Temperature, this, parameter, settings); moel@57: offset += sensorhubTemperatures.Length; moel@57: moel@57: for (int i = 0; i < miniNGTemperatures.Length; i++) moel@63: miniNGTemperatures[i] = new Sensor("miniNG #" + (i / 2 + 1) + moel@165: " Sensor " + (i % 2 + 1), offset + i, SensorType.Temperature, moel@165: this, parameter, settings); moel@57: offset += miniNGTemperatures.Length; moel@57: moel@118: for (int i = 0; i < sensorhubFlows.Length; i++) moel@118: sensorhubFlows[i] = new Sensor("Flowmeter " + (i + 1), moel@134: i, SensorType.Flow, this, new ParameterDescription[] { moel@118: new ParameterDescription("Impulse Rate", moel@118: "The impulse rate of the flowmeter in pulses/L", 509) moel@165: }, settings); moel@118: moel@118: for (int i = 0; i < controls.Length; i++) { moel@137: controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, moel@165: this, settings); moel@137: } moel@137: moel@137: for (int i = 0; i < miniNGControls.Length; i++) { moel@137: miniNGControls[i] = new Sensor("miniNG #" + (i / 2 + 1) + moel@165: " Fan Channel " + (i % 2 + 1), 4 + i, SensorType.Control, this, moel@165: settings); moel@118: } moel@118: moel@57: alternativeRequest = new MethodDelegate(DelayedAlternativeRequest); moel@57: moel@87: Open(); moel@87: Update(); moel@1: } moel@1: moel@1: private void ActivateSensor(Sensor sensor) { moel@1: deactivating.Remove(sensor); moel@1: if (!active.Contains(sensor)) { moel@1: active.Add(sensor); moel@15: if (SensorAdded != null) moel@15: SensorAdded(sensor); moel@1: } moel@1: } moel@1: moel@1: private void DeactivateSensor(Sensor sensor) { moel@1: if (deactivating.Contains(sensor)) { moel@1: active.Remove(sensor); moel@1: deactivating.Remove(sensor); moel@15: if (SensorRemoved != null) moel@15: SensorRemoved(sensor); moel@1: } else if (active.Contains(sensor)) { moel@1: deactivating.Add(sensor); moel@1: } moel@1: } moel@1: moel@57: private void ReadminiNG(int[] data, int number) { moel@57: int offset = 1 + number * 65; moel@57: moel@57: if (data[offset + 61] != ENDFLAG) moel@57: return; moel@57: moel@57: for (int i = 0; i < 2; i++) { moel@57: Sensor sensor = miniNGTemperatures[number * 2 + i]; moel@57: if (data[offset + 7 + i] > 0) { moel@63: sensor.Value = 0.5f * data[offset + 7 + i] + moel@63: sensor.Parameters[0].Value; moel@57: ActivateSensor(sensor); moel@57: } else { moel@57: DeactivateSensor(sensor); moel@57: } moel@57: } moel@57: moel@57: for (int i = 0; i < 2; i++) { moel@57: if (miniNGFans[number * 2 + i] == null) moel@57: miniNGFans[number * 2 + i] = moel@88: new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1), moel@165: 4 + number * 2 + i, SensorType.Fan, this, settings); moel@57: moel@57: Sensor sensor = miniNGFans[number * 2 + i]; moel@57: moel@57: sensor.Value = 20.0f * data[offset + 43 + 2 * i]; moel@57: ActivateSensor(sensor); moel@57: } moel@137: moel@137: for (int i = 0; i < 2; i++) { moel@137: Sensor sensor = miniNGControls[number * 2 + i]; moel@137: sensor.Value = data[offset + 15 + i]; moel@137: ActivateSensor(sensor); moel@137: } moel@57: } moel@57: moel@1: private void ReadData() { moel@1: int[] data = new int[285]; moel@1: for (int i = 0; i < data.Length; i++) moel@87: data[i] = FTD2XX.ReadByte(handle); moel@137: moel@57: if (data[0] != STARTFLAG) { moel@87: FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX); moel@1: return; moel@1: } moel@1: moel@73: if (data[1] == 255 || data[1] == 88) { // bigNG moel@57: moel@57: if (data[274] != protocolVersion) moel@57: return; moel@57: moel@57: this.primaryData = data; moel@57: moel@57: for (int i = 0; i < digitalTemperatures.Length; i++) moel@57: if (data[238 + i] > 0) { moel@63: digitalTemperatures[i].Value = 0.5f * data[238 + i] + moel@63: digitalTemperatures[i].Parameters[0].Value; moel@57: ActivateSensor(digitalTemperatures[i]); moel@57: } else { moel@57: DeactivateSensor(digitalTemperatures[i]); moel@57: } moel@57: moel@57: for (int i = 0; i < analogTemperatures.Length; i++) moel@57: if (data[260 + i] > 0) { moel@63: analogTemperatures[i].Value = 0.5f * data[260 + i] + moel@63: analogTemperatures[i].Parameters[0].Value; moel@57: ActivateSensor(analogTemperatures[i]); moel@57: } else { moel@57: DeactivateSensor(analogTemperatures[i]); moel@57: } moel@57: moel@57: for (int i = 0; i < sensorhubTemperatures.Length; i++) moel@57: if (data[246 + i] > 0) { moel@63: sensorhubTemperatures[i].Value = 0.5f * data[246 + i] + moel@63: sensorhubTemperatures[i].Parameters[0].Value; moel@57: ActivateSensor(sensorhubTemperatures[i]); moel@57: } else { moel@57: DeactivateSensor(sensorhubTemperatures[i]); moel@57: } moel@57: moel@57: for (int i = 0; i < sensorhubFlows.Length; i++) moel@57: if (data[231 + i] > 0 && data[234] > 0) { moel@66: float pulsesPerSecond = (data[231 + i] * 4.0f) / data[234]; moel@63: float pulsesPerLiter = sensorhubFlows[i].Parameters[0].Value; moel@57: sensorhubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter; moel@57: ActivateSensor(sensorhubFlows[i]); moel@57: } else { moel@57: DeactivateSensor(sensorhubFlows[i]); moel@57: } moel@86: moel@57: for (int i = 0; i < fans.Length; i++) { moel@57: float maxRPM = 11.5f * ((data[149 + 2 * i] << 8) | data[148 + 2 * i]); moel@57: moel@57: if (fans[i] == null) moel@134: fans[i] = new Sensor("Fan Channel " + i, i, SensorType.Fan, moel@63: this, new ParameterDescription[] { moel@63: new ParameterDescription("MaxRPM", moel@63: "Maximum revolutions per minute (RPM) of the fan.", maxRPM) moel@165: }, settings); moel@57: moel@118: float value; moel@118: if ((data[136] & (1 << i)) == 0) // pwm mode moel@118: value = 0.02f * data[137 + i]; moel@63: else // analog mode moel@118: value = 0.01f * data[141 + i]; moel@118: moel@118: fans[i].Value = fans[i].Parameters[0].Value * value; moel@57: ActivateSensor(fans[i]); moel@118: moel@137: controls[i].Value = 100 * value; moel@137: ActivateSensor(controls[i]); moel@1: } moel@1: moel@57: } else if (data[1] == 253) { // miniNG #1 moel@57: this.alternativeData = data; moel@1: moel@57: ReadminiNG(data, 0); moel@57: moel@137: if (data[66] == 253) // miniNG #2 moel@57: ReadminiNG(data, 1); moel@57: } moel@1: } moel@1: moel@165: public HardwareType HardwareType { moel@165: get { return HardwareType.TBalancer; } moel@1: } moel@1: moel@1: public string Name { moel@1: get { return "T-Balancer bigNG"; } moel@1: } moel@1: moel@109: public Identifier Identifier { moel@166: get { moel@166: return new Identifier("bigng", moel@166: this.portIndex.ToString(CultureInfo.InvariantCulture)); moel@166: } moel@1: } moel@1: moel@64: public IHardware[] SubHardware { moel@64: get { return new IHardware[0]; } moel@64: } moel@64: moel@1: public ISensor[] Sensors { moel@1: get { return active.ToArray(); } moel@1: } moel@1: moel@1: public string GetReport() { moel@1: StringBuilder r = new StringBuilder(); moel@1: moel@1: r.AppendLine("T-Balancer bigNG"); moel@1: r.AppendLine(); moel@166: r.Append("Port Index: "); moel@166: r.AppendLine(portIndex.ToString(CultureInfo.InvariantCulture)); moel@1: r.AppendLine(); moel@57: moel@57: r.AppendLine("Primary System Information Answer"); moel@1: r.AppendLine(); moel@1: r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); moel@1: r.AppendLine(); moel@1: for (int i = 0; i <= 0x11; i++) { moel@166: r.Append(" "); moel@166: r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); moel@166: r.Append(" "); moel@1: for (int j = 0; j <= 0xF; j++) { moel@1: int index = ((i << 4) | j); moel@57: if (index < primaryData.Length) { moel@1: r.Append(" "); moel@166: r.Append(primaryData[index].ToString("X2", CultureInfo.InvariantCulture)); moel@1: } moel@1: } moel@1: r.AppendLine(); moel@1: } moel@1: r.AppendLine(); moel@1: moel@57: if (alternativeData.Length > 0) { moel@57: r.AppendLine("Alternative System Information Answer"); moel@57: r.AppendLine(); moel@57: r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); moel@57: r.AppendLine(); moel@57: for (int i = 0; i <= 0x11; i++) { moel@166: r.Append(" "); moel@166: r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); moel@166: r.Append(" "); moel@57: for (int j = 0; j <= 0xF; j++) { moel@57: int index = ((i << 4) | j); moel@57: if (index < alternativeData.Length) { moel@57: r.Append(" "); moel@166: r.Append(alternativeData[index].ToString("X2", CultureInfo.InvariantCulture)); moel@57: } moel@57: } moel@57: r.AppendLine(); moel@57: } moel@57: r.AppendLine(); moel@57: } moel@57: moel@1: return r.ToString(); moel@1: } moel@1: moel@57: private void DelayedAlternativeRequest() { moel@87: System.Threading.Thread.Sleep(500); moel@87: FTD2XX.Write(handle, new byte[] { 0x37 }); moel@57: } moel@57: moel@87: public void Open() { moel@87: FTD2XX.FT_Open(portIndex, out handle); moel@87: FTD2XX.FT_SetBaudRate(handle, 19200); moel@87: FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0); moel@87: FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, moel@87: 0x13); moel@87: FTD2XX.FT_SetTimeouts(handle, 1000, 1000); moel@87: FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL); moel@87: } moel@57: moel@87: public void Update() { moel@87: while (FTD2XX.BytesToRead(handle) >= 285) moel@87: ReadData(); moel@87: if (FTD2XX.BytesToRead(handle) == 1) moel@87: FTD2XX.ReadByte(handle); moel@87: moel@87: FTD2XX.Write(handle, new byte[] { 0x38 }); moel@87: alternativeRequest.BeginInvoke(null, null); moel@1: } moel@1: moel@1: public void Close() { moel@87: FTD2XX.FT_Close(handle); moel@1: } moel@1: moel@1: public event SensorEventHandler SensorAdded; moel@1: public event SensorEventHandler SensorRemoved; moel@110: moel@110: public void Accept(IVisitor visitor) { moel@167: if (visitor == null) moel@167: throw new ArgumentNullException("visitor"); moel@167: visitor.VisitHardware(this); moel@110: } moel@110: moel@110: public void Traverse(IVisitor visitor) { } moel@1: } moel@1: }