Rewritten the T-Balancer code to use the FTDI D2XX drivers directly instead of the System.IO.Ports.SerialPort class. The SerialPort class has some ugly problems like http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port or http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8a1825d2-c84b-4620-91e7-3934a4d47330 for which no real solution seems to exist. And Microsoft doesn't feel like it needs to be fixed for years now.

This commit is contained in:
Michael Möller
2010-04-05 15:31:19 +00:00
parent 20158a0edd
commit 76a3ac113b
6 changed files with 368 additions and 132 deletions

View File

@@ -74,34 +74,37 @@ namespace OpenHardwareMonitor.GUI {
}
private void sendButton_Click(object sender, EventArgs e) {
Version version = typeof(CrashReportForm).Assembly.GetName().Version;
WebRequest request = WebRequest.Create(
"http://openhardwaremonitor.org/report.php");
request.Method = "POST";
request.Timeout = 3000;
request.ContentType = "application/x-www-form-urlencoded";
string report =
"version=" + HttpUtility.UrlEncode(version.ToString()) + "&" +
"report=" + HttpUtility.UrlEncode(reportTextBox.Text +
commentTextBox.Text);
byte[] byteArray = Encoding.UTF8.GetBytes(report);
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
try {
WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
Version version = typeof(CrashReportForm).Assembly.GetName().Version;
WebRequest request = WebRequest.Create(
"http://openhardwaremonitor.org/report.php");
request.Method = "POST";
request.Timeout = 3000;
request.ContentType = "application/x-www-form-urlencoded";
string report =
"version=" + HttpUtility.UrlEncode(version.ToString()) + "&" +
"report=" + HttpUtility.UrlEncode(reportTextBox.Text +
commentTextBox.Text);
byte[] byteArray = Encoding.UTF8.GetBytes(report);
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
response.Close();
} catch (WebException) {
try {
WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
} catch (WebException) {
}
} finally {
Close();
}
Close();
}
}
}

View File

@@ -0,0 +1,207 @@
/*
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Original Code is the Open Hardware Monitor code.
The Initial Developer of the Original Code is
Michael Möller <m.moeller@gmx.ch>.
Portions created by the Initial Developer are Copyright (C) 2009-2010
the Initial Developer. All Rights Reserved.
Contributor(s):
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace OpenHardwareMonitor.Hardware.TBalancer {
public enum FT_DEVICE : uint {
FT_DEVICE_BM,
FT_DEVICE_AM,
FT_DEVICE_100AX,
FT_DEVICE_UNKNOWN,
FT_DEVICE_2232,
FT_DEVICE_232R,
FT_DEVICE_2232H,
FT_DEVICE_4232H
}
public enum FT_STATUS {
FT_OK,
FT_INVALID_HANDLE,
FT_DEVICE_NOT_FOUND,
FT_DEVICE_NOT_OPENED,
FT_IO_ERROR,
FT_INSUFFICIENT_RESOURCES,
FT_INVALID_PARAMETER,
FT_INVALID_BAUD_RATE,
FT_DEVICE_NOT_OPENED_FOR_ERASE,
FT_DEVICE_NOT_OPENED_FOR_WRITE,
FT_FAILED_TO_WRITE_DEVICE,
FT_EEPROM_READ_FAILED,
FT_EEPROM_WRITE_FAILED,
FT_EEPROM_ERASE_FAILED,
FT_EEPROM_NOT_PRESENT,
FT_EEPROM_NOT_PROGRAMMED,
FT_INVALID_ARGS,
FT_OTHER_ERROR
}
public enum FT_FLOW_CONTROL : ushort {
FT_FLOW_DTR_DSR = 512,
FT_FLOW_NONE = 0,
FT_FLOW_RTS_CTS = 256,
FT_FLOW_XON_XOFF = 1024,
}
public enum FT_PURGE : uint {
FT_PURGE_RX = 1,
FT_PURGE_TX = 2,
FT_PURGE_ALL = 3,
}
[StructLayout(LayoutKind.Sequential)]
public struct FT_HANDLE {
private uint handle;
}
[StructLayout(LayoutKind.Sequential)]
public struct FT_DEVICE_INFO_NODE {
public uint Flags;
public FT_DEVICE Type;
public uint ID;
public uint LocId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string SerialNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string Description;
public FT_HANDLE Handle;
}
public class FTD2XX {
public delegate FT_STATUS FT_CreateDeviceInfoListDelegate(
out uint numDevices);
public delegate FT_STATUS FT_GetDeviceInfoListDelegate(
[Out] FT_DEVICE_INFO_NODE[] deviceInfoNodes, ref uint length);
public delegate FT_STATUS FT_OpenDelegate(int device, out FT_HANDLE handle);
public delegate FT_STATUS FT_CloseDelegate(FT_HANDLE handle);
public delegate FT_STATUS FT_SetBaudRateDelegate(FT_HANDLE handle,
uint baudRate);
public delegate FT_STATUS FT_SetDataCharacteristicsDelegate(
FT_HANDLE handle, byte wordLength, byte stopBits, byte parity);
public delegate FT_STATUS FT_SetFlowControlDelegate(FT_HANDLE handle,
FT_FLOW_CONTROL flowControl, byte xon, byte xoff);
public delegate FT_STATUS FT_SetTimeoutsDelegate(FT_HANDLE handle,
uint readTimeout, uint writeTimeout);
public delegate FT_STATUS FT_WriteDelegate(FT_HANDLE handle, byte[] buffer,
uint bytesToWrite, out uint bytesWritten);
public delegate FT_STATUS FT_PurgeDelegate(FT_HANDLE handle, FT_PURGE mask);
public delegate FT_STATUS FT_GetStatusDelegate(FT_HANDLE handle,
out uint amountInRxQueue, out uint amountInTxQueue, out uint eventStatus);
public delegate FT_STATUS FT_ReadDelegate(FT_HANDLE handle,
[Out] byte[] buffer, uint bytesToRead, out uint bytesReturned);
public static FT_CreateDeviceInfoListDelegate FT_CreateDeviceInfoList;
public static FT_GetDeviceInfoListDelegate FT_GetDeviceInfoList;
public static FT_OpenDelegate FT_Open;
public static FT_CloseDelegate FT_Close;
public static FT_SetBaudRateDelegate FT_SetBaudRate;
public static FT_SetDataCharacteristicsDelegate FT_SetDataCharacteristics;
public static FT_SetFlowControlDelegate FT_SetFlowControl;
public static FT_SetTimeoutsDelegate FT_SetTimeouts;
public static FT_WriteDelegate FT_Write;
public static FT_PurgeDelegate FT_Purge;
public static FT_GetStatusDelegate FT_GetStatus;
public static FT_ReadDelegate FT_Read;
public static FT_STATUS Write(FT_HANDLE handle, byte[] buffer) {
uint bytesWritten;
FT_STATUS status = FT_Write(handle, buffer, (uint)buffer.Length,
out bytesWritten);
if (bytesWritten != buffer.Length)
return FT_STATUS.FT_FAILED_TO_WRITE_DEVICE;
else
return status;
}
public static int BytesToRead(FT_HANDLE handle) {
uint amountInRxQueue;
uint amountInTxQueue;
uint eventStatus;
if (FT_GetStatus(handle, out amountInRxQueue, out amountInTxQueue,
out eventStatus) == FT_STATUS.FT_OK) {
return (int)amountInRxQueue;
} else {
return 0;
}
}
public static byte ReadByte(FT_HANDLE handle) {
byte[] buffer = new byte[1];
uint bytesReturned;
FT_STATUS status = FT_Read(handle, buffer, 1, out bytesReturned);
if (status != FT_STATUS.FT_OK || bytesReturned != 1)
throw new Exception();
return buffer[0];
}
private static string dllName;
private static void GetDelegate<T>(string entryPoint, out T newDelegate)
where T : class {
DllImportAttribute attribute = new DllImportAttribute(dllName);
attribute.CallingConvention = CallingConvention.StdCall;
attribute.PreserveSig = true;
attribute.EntryPoint = entryPoint;
PInvokeDelegateFactory.CreateDelegate(attribute, out newDelegate);
}
static FTD2XX() {
int p = (int)System.Environment.OSVersion.Platform;
if ((p == 4) || (p == 128))
dllName = "libftd2xx.so";
else
dllName = "ftd2xx.dll";
GetDelegate("FT_CreateDeviceInfoList", out FT_CreateDeviceInfoList);
GetDelegate("FT_GetDeviceInfoList", out FT_GetDeviceInfoList);
GetDelegate("FT_Open", out FT_Open);
GetDelegate("FT_Close", out FT_Close);
GetDelegate("FT_SetBaudRate", out FT_SetBaudRate);
GetDelegate("FT_SetDataCharacteristics", out FT_SetDataCharacteristics);
GetDelegate("FT_SetFlowControl", out FT_SetFlowControl);
GetDelegate("FT_SetTimeouts", out FT_SetTimeouts);
GetDelegate("FT_Write", out FT_Write);
GetDelegate("FT_Purge", out FT_Purge);
GetDelegate("FT_GetStatus", out FT_GetStatus);
GetDelegate("FT_Read", out FT_Read);
}
}
}

View File

@@ -39,16 +39,14 @@ using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
namespace OpenHardwareMonitor.Hardware.TBalancer {
public class TBalancer : IHardware {
private string portName;
private int portIndex;
private FT_HANDLE handle;
private Image icon;
private SerialPort serialPort;
private byte protocolVersion;
private Sensor[] digitalTemperatures = new Sensor[8];
private Sensor[] analogTemperatures = new Sensor[4];
@@ -68,8 +66,8 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
private delegate void MethodDelegate();
private MethodDelegate alternativeRequest;
public TBalancer(string portName, byte protocolVersion) {
this.portName = portName;
public TBalancer(int portIndex, byte protocolVersion) {
this.portIndex = portIndex;
this.icon = Utilities.EmbeddedResources.GetImage("bigng.png");
this.protocolVersion = protocolVersion;
@@ -108,12 +106,8 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
try {
serialPort = new SerialPort(portName, 19200, Parity.None, 8,
StopBits.One);
serialPort.Open();
Update();
} catch (IOException) { }
Open();
Update();
}
private void ActivateSensor(Sensor sensor) {
@@ -171,10 +165,10 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
private void ReadData() {
int[] data = new int[285];
for (int i = 0; i < data.Length; i++)
data[i] = serialPort.ReadByte();
data[i] = FTD2XX.ReadByte(handle);
if (data[0] != STARTFLAG) {
serialPort.DiscardInBuffer();
FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX);
return;
}
@@ -258,8 +252,7 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
}
public string Identifier {
get { return "/bigng/" +
this.portName.TrimStart(new char[]{'/'}).ToLower(); }
get { return "/bigng/" + this.portIndex; }
}
public IHardware[] SubHardware {
@@ -275,7 +268,7 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
r.AppendLine("T-Balancer bigNG");
r.AppendLine();
r.Append("Port Name: "); r.AppendLine(serialPort.PortName);
r.Append("Port Index: "); r.AppendLine(portIndex.ToString());
r.AppendLine();
r.AppendLine("Primary System Information Answer");
@@ -318,31 +311,32 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
}
private void DelayedAlternativeRequest() {
System.Threading.Thread.Sleep(500);
try {
if (serialPort.IsOpen)
serialPort.Write(new byte[] { 0x37 }, 0, 1);
} catch (Exception) { }
System.Threading.Thread.Sleep(500);
FTD2XX.Write(handle, new byte[] { 0x37 });
}
public void Update() {
try {
while (serialPort.IsOpen && serialPort.BytesToRead >= 285)
ReadData();
if (serialPort.BytesToRead == 1)
serialPort.ReadByte();
public void Open() {
FTD2XX.FT_Open(portIndex, out handle);
FTD2XX.FT_SetBaudRate(handle, 19200);
FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
0x13);
FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
}
serialPort.Write(new byte[] { 0x38 }, 0, 1);
alternativeRequest.BeginInvoke(null, null);
} catch (InvalidOperationException) {
foreach (Sensor sensor in active)
sensor.Value = null;
}
public void Update() {
while (FTD2XX.BytesToRead(handle) >= 285)
ReadData();
if (FTD2XX.BytesToRead(handle) == 1)
FTD2XX.ReadByte(handle);
FTD2XX.Write(handle, new byte[] { 0x38 });
alternativeRequest.BeginInvoke(null, null);
}
public void Close() {
if (serialPort.IsOpen)
serialPort.Close();
FTD2XX.FT_Close(handle);
}
public event SensorEventHandler SensorAdded;

View File

@@ -49,79 +49,87 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
private StringBuilder report = new StringBuilder();
public TBalancerGroup() {
string[] portNames = SerialPort.GetPortNames();
for (int i = portNames.Length - 1; i >= 0; i--) {
try {
SerialPort serialPort =
new SerialPort(portNames[i], 19200, Parity.None, 8, StopBits.One);
bool isValid = false;
byte protocolVersion = 0;
report.Append("Port Name: "); report.AppendLine(portNames[i]);
uint numDevices;
try {
FTD2XX.FT_CreateDeviceInfoList(out numDevices);
} catch (DllNotFoundException) { return; }
catch (ArgumentNullException) { return; }
FT_DEVICE_INFO_NODE[] info = new FT_DEVICE_INFO_NODE[numDevices];
FTD2XX.FT_GetDeviceInfoList(info, ref numDevices);
try {
serialPort.Open();
} catch (UnauthorizedAccessException) {
report.AppendLine("Exception: Access Denied");
}
if (serialPort.IsOpen) {
if (serialPort.CtsHolding) {
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Write(new byte[] { 0x38 }, 0, 1);
int j = 0;
while (serialPort.BytesToRead == 0 && j < 2) {
Thread.Sleep(100);
j++;
}
if (serialPort.BytesToRead > 0) {
if (serialPort.ReadByte() == TBalancer.STARTFLAG) {
while (serialPort.BytesToRead < 284 && j < 5) {
Thread.Sleep(100);
j++;
}
int length = serialPort.BytesToRead;
if (length >= 284) {
byte[] data = new byte[285];
data[0] = TBalancer.STARTFLAG;
for (int k = 1; k < data.Length; k++)
data[k] = (byte)serialPort.ReadByte();
for (int i = 0; i < numDevices; i++) {
report.Append("Device Index: "); report.AppendLine(i.ToString());
FT_HANDLE handle;
FT_STATUS status;
status = FTD2XX.FT_Open(i, out handle);
if (status != FT_STATUS.FT_OK) {
report.AppendLine("Open Status: " + status);
continue;
}
// check protocol version 2X (protocols seen: 2C, 2A, 28)
isValid = (data[274] & 0xF0) == 0x20;
protocolVersion = data[274];
if (!isValid) {
report.Append("Status: Wrong Protocol Version: 0x");
report.AppendLine(protocolVersion.ToString("X"));
}
} else {
report.AppendLine("Status: Wrong Message Length: " +length);
}
} else {
report.AppendLine("Status: Wrong Startflag");
}
} else {
report.AppendLine("Status: No Response");
FTD2XX.FT_SetBaudRate(handle, 19200);
FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
0x13);
FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
status = FTD2XX.Write(handle, new byte[] { 0x38 });
if (status != FT_STATUS.FT_OK) {
report.AppendLine("Write Status: " + status);
FTD2XX.FT_Close(handle);
continue;
}
bool isValid = false;
byte protocolVersion = 0;
int j = 0;
while (FTD2XX.BytesToRead(handle) == 0 && j < 2) {
Thread.Sleep(100);
j++;
}
if (FTD2XX.BytesToRead(handle) > 0) {
if (FTD2XX.ReadByte(handle) == TBalancer.STARTFLAG) {
while (FTD2XX.BytesToRead(handle) < 284 && j < 5) {
Thread.Sleep(100);
j++;
}
int length = FTD2XX.BytesToRead(handle);
if (length >= 284) {
byte[] data = new byte[285];
data[0] = TBalancer.STARTFLAG;
for (int k = 1; k < data.Length; k++)
data[k] = FTD2XX.ReadByte(handle);
// check protocol version 2X (protocols seen: 2C, 2A, 28)
isValid = (data[274] & 0xF0) == 0x20;
protocolVersion = data[274];
if (!isValid) {
report.Append("Status: Wrong Protocol Version: 0x");
report.AppendLine(protocolVersion.ToString("X"));
}
} else {
report.AppendLine("Status: Not Clear to Send");
report.AppendLine("Status: Wrong Message Length: " + length);
}
serialPort.DiscardInBuffer();
serialPort.Close();
} else {
report.AppendLine("Status: Port not Open");
}
if (isValid) {
report.AppendLine("Status: OK");
hardware.Add(new TBalancer(portNames[i], protocolVersion));
return;
} else {
report.AppendLine("Status: Wrong Startflag");
}
} catch (Exception e) {
report.AppendLine(e.ToString());
}
} else {
report.AppendLine("Status: No Response");
}
FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
FTD2XX.FT_Close(handle);
if (isValid) {
report.AppendLine("Status: OK");
hardware.Add(new TBalancer(i, protocolVersion));
return;
}
report.AppendLine();
}
}
@@ -134,7 +142,7 @@ namespace OpenHardwareMonitor.Hardware.TBalancer {
public string GetReport() {
if (report.Length > 0) {
report.Insert(0, "Serial Port T-Balancer" + Environment.NewLine +
report.Insert(0, "FTD2XX" + Environment.NewLine +
Environment.NewLine);
report.AppendLine();
return report.ToString();

View File

@@ -95,6 +95,7 @@
<Compile Include="Hardware\Mainboard\SMBIOS.cs" />
<Compile Include="Hardware\LPC\W836XX.cs" />
<Compile Include="Hardware\Computer.cs" />
<Compile Include="Hardware\TBalancer\FTD2XX.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GUI\AboutBox.cs">
<SubType>Form</SubType>

View File

@@ -48,6 +48,11 @@ namespace OpenHardwareMonitor {
[STAThread]
public static void Main() {
#if !DEBUG
Application.ThreadException +=
new ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
#endif
@@ -62,13 +67,31 @@ namespace OpenHardwareMonitor {
}
}
private static void ReportException(Exception e) {
CrashReportForm form = new CrashReportForm();
form.Exception = e;
form.ShowDialog();
}
public static void Application_ThreadException(object sender,
ThreadExceptionEventArgs e)
{
try {
ReportException(e.Exception);
} catch {
} finally {
Application.Exit();
}
}
public static void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs args)
{
CrashReportForm form = new CrashReportForm();
form.Exception = (Exception)args.ExceptionObject;
form.ShowDialog();
Environment.Exit(0);
try {
Exception e = args.ExceptionObject as Exception;
if (e != null)
ReportException(e);
} catch { }
}
}
}