Converted project to VisualStudio 2012.
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
11 using System.Globalization;
15 namespace OpenHardwareMonitor.Hardware.LPC {
16 internal class IT87XX : ISuperIO {
18 private readonly ushort address;
19 private readonly Chip chip;
20 private readonly byte version;
22 private readonly ushort gpioAddress;
23 private readonly int gpioCount;
25 private readonly ushort addressReg;
26 private readonly ushort dataReg;
28 private readonly float?[] voltages = new float?[0];
29 private readonly float?[] temperatures = new float?[0];
30 private readonly float?[] fans = new float?[0];
31 private readonly float?[] controls = new float?[0];
33 private readonly float voltageGain;
34 private readonly bool has16bitFanCounter;
37 private const byte ITE_VENDOR_ID = 0x90;
39 // Environment Controller
40 private const byte ADDRESS_REGISTER_OFFSET = 0x05;
41 private const byte DATA_REGISTER_OFFSET = 0x06;
43 // Environment Controller Registers
44 private const byte CONFIGURATION_REGISTER = 0x00;
45 private const byte TEMPERATURE_BASE_REG = 0x29;
46 private const byte VENDOR_ID_REGISTER = 0x58;
47 private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
48 private readonly byte[] FAN_TACHOMETER_REG =
49 { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
50 private readonly byte[] FAN_TACHOMETER_EXT_REG =
51 { 0x18, 0x19, 0x1a, 0x81, 0x83 };
52 private const byte VOLTAGE_BASE_REG = 0x20;
53 private readonly byte[] FAN_PWM_CTRL_REG = { 0x15, 0x16, 0x17 };
55 private bool[] restoreDefaultFanPwmControlRequired = new bool[3];
56 private byte[] initialFanPwmControl = new byte[3];
58 private byte ReadByte(byte register, out bool valid) {
59 Ring0.WriteIoPort(addressReg, register);
60 byte value = Ring0.ReadIoPort(dataReg);
61 valid = register == Ring0.ReadIoPort(addressReg);
65 private bool WriteByte(byte register, byte value) {
66 Ring0.WriteIoPort(addressReg, register);
67 Ring0.WriteIoPort(dataReg, value);
68 return register == Ring0.ReadIoPort(addressReg);
71 public byte? ReadGPIO(int index) {
72 if (index >= gpioCount)
75 return Ring0.ReadIoPort((ushort)(gpioAddress + index));
78 public void WriteGPIO(int index, byte value) {
79 if (index >= gpioCount)
82 Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
85 private void SaveDefaultFanPwmControl(int index) {
87 if (!restoreDefaultFanPwmControlRequired[index]) {
88 initialFanPwmControl[index] =
89 ReadByte(FAN_PWM_CTRL_REG[index], out valid);
90 restoreDefaultFanPwmControlRequired[index] = true;
94 private void RestoreDefaultFanPwmControl(int index) {
95 if (restoreDefaultFanPwmControlRequired[index]) {
96 WriteByte(FAN_PWM_CTRL_REG[index], initialFanPwmControl[index]);
97 restoreDefaultFanPwmControlRequired[index] = false;
101 public void SetControl(int index, byte? value) {
102 if (index < 0 || index >= controls.Length)
103 throw new ArgumentOutOfRangeException("index");
105 if (!Ring0.WaitIsaBusMutex(10))
108 if (value.HasValue) {
109 SaveDefaultFanPwmControl(index);
112 WriteByte(FAN_PWM_CTRL_REG[index], (byte)(value.Value >> 1));
114 RestoreDefaultFanPwmControl(index);
117 Ring0.ReleaseIsaBusMutex();
120 public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
122 this.address = address;
124 this.version = version;
125 this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
126 this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
127 this.gpioAddress = gpioAddress;
131 byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);
132 if (!valid || vendorId != ITE_VENDOR_ID)
135 // Bit 0x10 of the configuration register should always be 1
136 if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
141 voltages = new float?[9];
142 temperatures = new float?[3];
143 fans = new float?[chip == Chip.IT8705F ? 3 : 5];
144 controls = new float?[3];
146 // IT8721F, IT8728F and IT8772E use a 12mV resultion ADC, all others 16mV
147 if (chip == Chip.IT8721F || chip == Chip.IT8728F || chip == Chip.IT8771E
148 || chip == Chip.IT8772E)
150 voltageGain = 0.012f;
152 voltageGain = 0.016f;
155 // older IT8705F and IT8721F revisions do not have 16-bit fan counters
156 if ((chip == Chip.IT8705F && version < 3) ||
157 (chip == Chip.IT8712F && version < 8))
159 has16bitFanCounter = false;
161 has16bitFanCounter = true;
164 // Set the number of GPIO sets
185 public Chip Chip { get { return chip; } }
186 public float?[] Voltages { get { return voltages; } }
187 public float?[] Temperatures { get { return temperatures; } }
188 public float?[] Fans { get { return fans; } }
189 public float?[] Controls { get { return controls; } }
191 public string GetReport() {
192 StringBuilder r = new StringBuilder();
194 r.AppendLine("LPC " + this.GetType().Name);
196 r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
197 r.Append("Chip Version: 0x"); r.AppendLine(
198 version.ToString("X", CultureInfo.InvariantCulture));
199 r.Append("Base Address: 0x"); r.AppendLine(
200 address.ToString("X4", CultureInfo.InvariantCulture));
201 r.Append("GPIO Address: 0x"); r.AppendLine(
202 gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
205 if (!Ring0.WaitIsaBusMutex(100))
208 r.AppendLine("Environment Controller Registers");
210 r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
212 for (int i = 0; i <= 0xA; i++) {
214 r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture));
216 for (int j = 0; j <= 0xF; j++) {
219 byte value = ReadByte((byte)((i << 4) | j), out valid);
221 valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
227 r.AppendLine("GPIO Registers");
229 for (int i = 0; i < gpioCount; i++) {
231 r.Append(ReadGPIO(i).Value.ToString("X2",
232 CultureInfo.InvariantCulture));
237 Ring0.ReleaseIsaBusMutex();
242 public void Update() {
243 if (!Ring0.WaitIsaBusMutex(10))
246 for (int i = 0; i < voltages.Length; i++) {
250 voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);
260 for (int i = 0; i < temperatures.Length; i++) {
262 sbyte value = (sbyte)ReadByte(
263 (byte)(TEMPERATURE_BASE_REG + i), out valid);
267 if (value < sbyte.MaxValue && value > 0)
268 temperatures[i] = value;
270 temperatures[i] = null;
273 if (has16bitFanCounter) {
274 for (int i = 0; i < fans.Length; i++) {
276 int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
279 value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
284 fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
290 for (int i = 0; i < fans.Length; i++) {
292 int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
298 int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
301 divisor = 1 << ((divisors >> (3 * i)) & 0x7);
305 fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
312 for (int i = 0; i < controls.Length; i++) {
314 byte value = ReadByte(FAN_PWM_CTRL_REG[i], out valid);
318 if ((value & 0x80) > 0) {
319 // automatic operation (value can't be read)
322 // software operation
323 controls[i] = (float)Math.Round((value & 0x7F) * 100.0f / 0x7F);
327 Ring0.ReleaseIsaBusMutex();