moel@1: /* moel@1: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@1: moel@344: Copyright (C) 2009-2011 Michael Möller moel@344: moel@1: */ moel@1: moel@1: using System; moel@1: using System.Collections.Generic; moel@166: using System.Globalization; moel@1: using System.Text; moel@1: moel@1: namespace OpenHardwareMonitor.Hardware.TBalancer { moel@275: internal class TBalancer : Hardware { moel@1: moel@195: private readonly int portIndex; moel@195: private readonly byte protocolVersion; moel@195: private readonly Sensor[] digitalTemperatures = new Sensor[8]; moel@195: private readonly Sensor[] analogTemperatures = new Sensor[4]; moel@195: private readonly Sensor[] sensorhubTemperatures = new Sensor[6]; moel@195: private readonly Sensor[] sensorhubFlows = new Sensor[2]; moel@195: private readonly Sensor[] fans = new Sensor[4]; moel@195: private readonly Sensor[] controls = new Sensor[4]; moel@195: private readonly Sensor[] miniNGTemperatures = new Sensor[4]; moel@195: private readonly Sensor[] miniNGFans = new Sensor[4]; moel@195: private readonly Sensor[] miniNGControls = new Sensor[4]; moel@195: private readonly List deactivating = new List(); moel@195: moel@87: private FT_HANDLE handle; 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@275: private readonly MethodDelegate alternativeRequest; moel@1: moel@275: public TBalancer(int portIndex, byte protocolVersion, ISettings settings) moel@275: : base("T-Balancer bigNG", new Identifier("bigng", moel@275: portIndex.ToString(CultureInfo.InvariantCulture)), settings) moel@275: { moel@165: moel@87: this.portIndex = portIndex; moel@33: this.protocolVersion = protocolVersion; moel@1: moel@195: ParameterDescription[] parameter = new [] { 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@195: i, SensorType.Flow, this, new [] { 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@275: protected override void ActivateSensor(ISensor sensor) { moel@1: deactivating.Remove(sensor); moel@275: base.ActivateSensor(sensor); moel@275: } moel@1: moel@275: protected override void DeactivateSensor(ISensor sensor) { moel@1: if (deactivating.Contains(sensor)) { moel@1: deactivating.Remove(sensor); moel@275: base.DeactivateSensor(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@195: this, new [] { 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@275: public override HardwareType HardwareType { moel@165: get { return HardwareType.TBalancer; } moel@1: } moel@1: moel@275: public override 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@275: public override 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@298: public override void Close() { moel@87: FTD2XX.FT_Close(handle); moel@298: base.Close(); moel@1: } moel@1: moel@1: } moel@1: }