# HG changeset patch # User moel.mich # Date 1270481479 0 # Node ID ecdc3bcef083ea4d36d1122b9cec0969257abe1d # Parent b4f0f206173d1137ce24ccd8ade569ef40304add 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. diff -r b4f0f206173d -r ecdc3bcef083 GUI/CrashReportForm.cs --- a/GUI/CrashReportForm.cs Fri Apr 02 16:05:07 2010 +0000 +++ b/GUI/CrashReportForm.cs Mon Apr 05 15:31:19 2010 +0000 @@ -74,34 +74,37 @@ } 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"; + try { + 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(); + 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(); } } } diff -r b4f0f206173d -r ecdc3bcef083 Hardware/TBalancer/FTD2XX.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Hardware/TBalancer/FTD2XX.cs Mon Apr 05 15:31:19 2010 +0000 @@ -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 . + 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(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); + } + } +} diff -r b4f0f206173d -r ecdc3bcef083 Hardware/TBalancer/TBalancer.cs --- a/Hardware/TBalancer/TBalancer.cs Fri Apr 02 16:05:07 2010 +0000 +++ b/Hardware/TBalancer/TBalancer.cs Mon Apr 05 15:31:19 2010 +0000 @@ -39,16 +39,14 @@ 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 @@ 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 @@ 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 @@ 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 @@ } public string Identifier { - get { return "/bigng/" + - this.portName.TrimStart(new char[]{'/'}).ToLower(); } + get { return "/bigng/" + this.portIndex; } } public IHardware[] SubHardware { @@ -275,7 +268,7 @@ 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 @@ } 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; diff -r b4f0f206173d -r ecdc3bcef083 Hardware/TBalancer/TBalancerGroup.cs --- a/Hardware/TBalancer/TBalancerGroup.cs Fri Apr 02 16:05:07 2010 +0000 +++ b/Hardware/TBalancer/TBalancerGroup.cs Mon Apr 05 15:31:19 2010 +0000 @@ -49,79 +49,87 @@ 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 @@ 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(); diff -r b4f0f206173d -r ecdc3bcef083 OpenHardwareMonitor.csproj --- a/OpenHardwareMonitor.csproj Fri Apr 02 16:05:07 2010 +0000 +++ b/OpenHardwareMonitor.csproj Mon Apr 05 15:31:19 2010 +0000 @@ -95,6 +95,7 @@ + Form diff -r b4f0f206173d -r ecdc3bcef083 Program.cs --- a/Program.cs Fri Apr 02 16:05:07 2010 +0000 +++ b/Program.cs Mon Apr 05 15:31:19 2010 +0000 @@ -48,6 +48,11 @@ [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 @@ } } + 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 { } } } }